From 5e7fed1f35c1318092fc6bf6d25814026224af8a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 1 Jul 2021 08:00:21 +0900 Subject: [PATCH 01/52] Add a regression test for issue-63355 --- .../ui/type-alias-impl-trait/issue-63355.rs | 50 +++++++++++++++++++ .../type-alias-impl-trait/issue-63355.stderr | 14 ++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/ui/type-alias-impl-trait/issue-63355.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-63355.stderr diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.rs b/src/test/ui/type-alias-impl-trait/issue-63355.rs new file mode 100644 index 0000000000000..8762d189c7389 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.rs @@ -0,0 +1,50 @@ +#![feature(min_type_alias_impl_trait)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +pub trait Foo {} + +pub trait Bar { + type Foo: Foo; + + fn foo() -> Self::Foo; +} + +pub trait Baz { + type Foo: Foo; + type Bar: Bar; + + fn foo() -> Self::Foo; + fn bar() -> Self::Bar; +} + +impl Foo for () {} + +impl Bar for () { + type Foo = FooImpl; + + fn foo() -> Self::Foo { + () + } +} + +// FIXME(#86731): The below is illegal use of `min_type_alias_impl_trait` +// but the compiler doesn't report it, we should fix it. +pub type FooImpl = impl Foo; +pub type BarImpl = impl Bar; +//~^ ERROR: type mismatch resolving `<() as Bar>::Foo == ()` + +impl Baz for () { + type Foo = FooImpl; + type Bar = BarImpl; + + fn foo() -> Self::Foo { + () + } + + fn bar() -> Self::Bar { + () + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.stderr b/src/test/ui/type-alias-impl-trait/issue-63355.stderr new file mode 100644 index 0000000000000..dc5370a2666b7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.stderr @@ -0,0 +1,14 @@ +error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()` + --> $DIR/issue-63355.rs:34:20 + | +LL | pub type FooImpl = impl Foo; + | -------- the found opaque type +LL | pub type BarImpl = impl Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `impl Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. From 5c9bd9c2b4fdca00410209d4c33edc3bebc63444 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 2 Jul 2021 11:30:20 -0500 Subject: [PATCH 02/52] Recover from a misplaced inner doc comment Fixes #86781 --- compiler/rustc_parse/src/parser/attr.rs | 9 ++++++++- src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs | 11 +++++++++++ .../ui/proc-macro/issue-86781-bad-inner-doc.stderr | 11 +++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs create mode 100644 src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 8b050389078a6..e9f0038b2d65d 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -64,7 +64,14 @@ impl<'a> Parser<'a> { } self.bump(); just_parsed_doc_comment = true; - Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span)) + // Always make an outer attribute - this allows us to recover from a misplaced + // inner attribute. + Some(attr::mk_doc_comment( + comment_kind, + ast::AttrStyle::Outer, + data, + self.prev_token.span, + )) } else { None }; diff --git a/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs new file mode 100644 index 0000000000000..8be1ae77738e9 --- /dev/null +++ b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs @@ -0,0 +1,11 @@ +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +//! Inner doc comment +//~^ ERROR expected outer doc comment +#[derive(Empty)] +pub struct Foo; + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr new file mode 100644 index 0000000000000..0b2e612ee5bb9 --- /dev/null +++ b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr @@ -0,0 +1,11 @@ +error[E0753]: expected outer doc comment + --> $DIR/issue-86781-bad-inner-doc.rs:6:1 + | +LL | //! Inner doc comment + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0753`. From 34ff25951b6ed50c4ef3d58c0417990815fd3829 Mon Sep 17 00:00:00 2001 From: Paul Trojahn Date: Wed, 19 May 2021 18:40:47 +0200 Subject: [PATCH 03/52] Add help on reinitialization between move and access Fixes #83760 --- .../diagnostics/conflict_errors.rs | 92 +++++++++++++++---- src/test/ui/borrowck/issue-83760.rs | 40 ++++++++ src/test/ui/borrowck/issue-83760.stderr | 62 +++++++++++++ 3 files changed, 176 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/borrowck/issue-83760.rs create mode 100644 src/test/ui/borrowck/issue-83760.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 0b01c4efcdbd4..2e854ea5be7df 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use crate::dataflow::drop_flag_effects; @@ -66,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location)); let span = use_spans.args_or_use(); - let move_site_vec = self.get_moved_indexes(location, mpi); + let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi); debug!( "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", move_site_vec, use_spans @@ -139,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); + let reinit_spans = maybe_reinitialized_locations + .iter() + .take(3) + .map(|loc| { + self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc) + .args_or_use() + }) + .collect::>(); + let reinits = maybe_reinitialized_locations.len(); + if reinits == 1 { + err.span_label(reinit_spans[0], "this reinitialization might get skipped"); + } else if reinits > 1 { + err.span_note( + MultiSpan::from_spans(reinit_spans), + &if reinits <= 3 { + format!("these {} reinitializations might get skipped", reinits) + } else { + format!( + "these 3 reinitializations and {} other{} might get skipped", + reinits - 3, + if reinits == 4 { "" } else { "s" } + ) + }, + ); + } + self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; @@ -219,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), ); } - if is_option_or_result { + if is_option_or_result && maybe_reinitialized_locations.is_empty() { err.span_suggestion_verbose( fn_call_span.shrink_to_lo(), "consider calling `.as_ref()` to borrow the type's contents", @@ -260,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - if let UseSpans::PatUse(span) = move_spans { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "borrow this field in the pattern to avoid moving {}", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the value".to_string()) - ), - "ref ".to_string(), - Applicability::MachineApplicable, - ); - in_pattern = true; + if let (UseSpans::PatUse(span), []) = + (move_spans, &maybe_reinitialized_locations[..]) + { + if maybe_reinitialized_locations.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "borrow this field in the pattern to avoid moving {}", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the value".to_string()) + ), + "ref ".to_string(), + Applicability::MachineApplicable, + ); + in_pattern = true; + } } if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { @@ -1465,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec { + fn get_moved_indexes( + &mut self, + location: Location, + mpi: MovePathIndex, + ) -> (Vec, Vec) { fn predecessor_locations( body: &'a mir::Body<'tcx>, location: Location, @@ -1488,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { })); let mut visited = FxHashSet::default(); + let mut move_locations = FxHashSet::default(); + let mut reinits = vec![]; let mut result = vec![]; 'dfs: while let Some((location, is_back_edge)) = stack.pop() { @@ -1529,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_paths[path].place ); result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); + move_locations.insert(location); // Strictly speaking, we could continue our DFS here. There may be // other moves that can reach the point of error. But it is kind of @@ -1565,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ); if any_match { + reinits.push(location); continue 'dfs; } @@ -1574,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { })); } - result + // Check if we can reach these reinits from a move location. + let reinits_reachable = reinits + .into_iter() + .filter(|reinit| { + let mut visited = FxHashSet::default(); + let mut stack = vec![*reinit]; + while let Some(location) = stack.pop() { + if !visited.insert(location) { + continue; + } + if move_locations.contains(&location) { + return true; + } + stack.extend(predecessor_locations(self.body, location)); + } + false + }) + .collect::>(); + (result, reinits_reachable) } pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed( diff --git a/src/test/ui/borrowck/issue-83760.rs b/src/test/ui/borrowck/issue-83760.rs new file mode 100644 index 0000000000000..e25b4f727856e --- /dev/null +++ b/src/test/ui/borrowck/issue-83760.rs @@ -0,0 +1,40 @@ +struct Struct; + +fn test1() { + let mut val = Some(Struct); + while let Some(foo) = val { //~ ERROR use of moved value + if true { + val = None; + } else { + + } + } +} + +fn test2() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn test3() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-83760.stderr b/src/test/ui/borrowck/issue-83760.stderr new file mode 100644 index 0000000000000..beeda5685dc09 --- /dev/null +++ b/src/test/ui/borrowck/issue-83760.stderr @@ -0,0 +1,62 @@ +error[E0382]: use of moved value + --> $DIR/issue-83760.rs:5:20 + | +LL | while let Some(foo) = val { + | ^^^ value moved here, in previous iteration of loop +LL | if true { +LL | val = None; + | ---------- this reinitialization might get skipped + | + = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:21:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +LL | if true { +LL | foo = Some(Struct); + | ------------------ this reinitialization might get skipped +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:37:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: these 3 reinitializations and 1 other might get skipped + --> $DIR/issue-83760.rs:30:9 + | +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. From ae33a9714e73dda15030894821b6819f781ed7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 7 Jul 2021 00:00:00 +0000 Subject: [PATCH 04/52] Set personality with LLVMSetPersonalityFn --- compiler/rustc_codegen_llvm/src/builder.rs | 6 +++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 582c9354041de..981ea95f2e06a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -937,8 +937,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { pers_fn: &'ll Value, num_clauses: usize, ) -> &'ll Value { + // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while, + // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The + // personality lives on the parent function anyway. + self.set_personality_fn(pers_fn); unsafe { - llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn, num_clauses as c_uint, UNNAMED) + llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 91923251018a8..b513e83bd1994 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1165,7 +1165,7 @@ extern "C" { pub fn LLVMBuildLandingPad( B: &Builder<'a>, Ty: &'a Type, - PersFn: &'a Value, + PersFn: Option<&'a Value>, NumClauses: c_uint, Name: *const c_char, ) -> &'a Value; From f612ba1f846c0e9ee16b0f19dd7a3719d1dddd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 7 Jul 2021 00:00:00 +0000 Subject: [PATCH 05/52] Use existing declaration of rust_eh_personality If crate declares `rust_eh_personality`, re-use existing declaration as otherwise attempts to set function attributes that follow the declaration will fail (unless it happens to have exactly the same type signature as the one predefined in the compiler). --- compiler/rustc_codegen_llvm/src/context.rs | 11 ++++++--- .../ui/panic-runtime/incompatible-type.rs | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/panic-runtime/incompatible-type.rs diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d1aecd32e2f2d..cccf2f8498cb8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -385,11 +385,16 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { "rust_eh_personality" }; - let fty = self.type_variadic_func(&[], self.type_i32()); - self.declare_cfn(name, llvm::UnnamedAddr::Global, fty) + if let Some(llfn) = self.get_declared_value(name) { + llfn + } else { + let fty = self.type_variadic_func(&[], self.type_i32()); + let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty); + attributes::apply_target_cpu_attr(self, llfn); + llfn + } } }; - attributes::apply_target_cpu_attr(self, llfn); self.eh_personality.set(Some(llfn)); llfn } diff --git a/src/test/ui/panic-runtime/incompatible-type.rs b/src/test/ui/panic-runtime/incompatible-type.rs new file mode 100644 index 0000000000000..026364a2058fa --- /dev/null +++ b/src/test/ui/panic-runtime/incompatible-type.rs @@ -0,0 +1,24 @@ +// Check that rust_eh_personality can have a different type signature than the +// one hardcoded in the compiler. Regression test for #70117. Used to fail with: +// +// Assertion `isa(Val) && "cast() argument of incompatible type!"' failed. +// +// build-pass +// compile-flags: --crate-type=lib -Ccodegen-units=1 +#![no_std] +#![panic_runtime] +#![feature(panic_runtime)] +#![feature(rustc_attrs)] + +pub struct DropMe; + +impl Drop for DropMe { + fn drop(&mut self) {} +} + +pub fn test(_: DropMe) { + unreachable!(); +} + +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn rust_eh_personality() {} From fd406a8865d601572ac0252ea57965e8b784de28 Mon Sep 17 00:00:00 2001 From: Aris Merchant <22333129+inquisitivecrystal@users.noreply.github.com> Date: Fri, 25 Jun 2021 19:46:41 -0700 Subject: [PATCH 06/52] Give a helpful error for the mistake `..==` --- compiler/rustc_parse/src/parser/expr.rs | 10 ++++--- compiler/rustc_parse/src/parser/pat.rs | 39 +++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9dff40ff1ed6e..5d765a474ae06 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -431,7 +431,8 @@ impl<'a> Parser<'a> { let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; - Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits), AttrVec::new())) + let range = self.mk_range(Some(lhs), rhs, limits); + Ok(self.mk_expr(span, range, AttrVec::new())) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -479,7 +480,8 @@ impl<'a> Parser<'a> { } else { (lo, None) }; - Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits), attrs.into())) + let range = this.mk_range(None, opt_end, limits); + Ok(this.mk_expr(span, range, attrs.into())) }) } @@ -2517,13 +2519,13 @@ impl<'a> Parser<'a> { } fn mk_range( - &self, + &mut self, start: Option>, end: Option>, limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.error_inclusive_range_with_no_end(self.prev_token.span); + self.inclusive_range_with_incorrect_end(self.prev_token.span); ExprKind::Err } else { ExprKind::Range(start, end, limits) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 566677d032aff..7d07c3b121195 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -736,15 +736,48 @@ impl<'a> Parser<'a> { // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. - // Possibly also do this for `X..=` in *expression* contexts. - self.error_inclusive_range_with_no_end(re.span); + self.inclusive_range_with_incorrect_end(re.span); } None }; Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) { + let tok = &self.token; + + // If the user typed "..==" instead of "..=", we want to give them + // a specific error message telling them to use "..=". + // Otherwise, we assume that they meant to type a half open exclusive + // range and give them an error telling them to do that instead. + if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() { + let span_with_eq = span.to(tok.span); + + // Ensure the user doesn't receive unhelpful unexpected token errors + self.bump(); + if self.is_pat_range_end_start(0) { + let _ = self.parse_pat_range_end(); + } + + self.error_inclusive_range_with_extra_equals(span_with_eq); + } else { + self.error_inclusive_range_with_no_end(span); + } + } + + fn error_inclusive_range_with_extra_equals(&self, span: Span) { + self.struct_span_err(span, "unexpected `=` after inclusive range") + .span_suggestion_short( + span, + "use `..=` instead", + "..=".to_string(), + Applicability::MaybeIncorrect, + ) + .note("inclusive ranges end with a single equals sign (`..=`)") + .emit(); + } + + fn error_inclusive_range_with_no_end(&self, span: Span) { struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") .span_suggestion_short( span, From b56079ec5466af5bff7d7d174ed6ae248aaa92c4 Mon Sep 17 00:00:00 2001 From: inquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com> Date: Sun, 11 Jul 2021 16:51:56 -0700 Subject: [PATCH 07/52] Add diagnostics test for mistyped inclusive ranges --- src/test/ui/parser/range-inclusive-extra-equals.rs | 10 ++++++++++ src/test/ui/parser/range-inclusive-extra-equals.stderr | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/parser/range-inclusive-extra-equals.rs create mode 100644 src/test/ui/parser/range-inclusive-extra-equals.stderr diff --git a/src/test/ui/parser/range-inclusive-extra-equals.rs b/src/test/ui/parser/range-inclusive-extra-equals.rs new file mode 100644 index 0000000000000..d41c0699cf7fb --- /dev/null +++ b/src/test/ui/parser/range-inclusive-extra-equals.rs @@ -0,0 +1,10 @@ +// Makes sure that a helpful message is shown when someone mistypes +// an inclusive range as `..==` rather than `..=`. This is an +// easy mistake, because of the resemblance to`==`. +// See #86395 for a bit of background. + +pub fn main() { + if let 1..==3 = 1 {} //~ERROR unexpected `=` after inclusive range + //~|HELP use `..=` instead + //~|NOTE inclusive ranges end with a single equals sign +} diff --git a/src/test/ui/parser/range-inclusive-extra-equals.stderr b/src/test/ui/parser/range-inclusive-extra-equals.stderr new file mode 100644 index 0000000000000..d37b6be4fa113 --- /dev/null +++ b/src/test/ui/parser/range-inclusive-extra-equals.stderr @@ -0,0 +1,10 @@ +error: unexpected `=` after inclusive range + --> $DIR/range-inclusive-extra-equals.rs:7:13 + | +LL | if let 1..==3 = 1 {} + | ^^^^ help: use `..=` instead + | + = note: inclusive ranges end with a single equals sign (`..=`) + +error: aborting due to previous error + From e32eceefe1ca3efeef123309eaa154d27d31788b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 5 Jul 2021 12:35:02 -0400 Subject: [PATCH 08/52] Remove unnecessary CrateNum from Cache.externs It can be found from ExternalCrate. --- src/librustdoc/clean/types.rs | 6 +++--- src/librustdoc/clean/utils.rs | 10 +++++----- src/librustdoc/formats/cache.rs | 9 ++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e716e09b8b3f0..1d3a8c7a8b334 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ crate struct Crate { crate name: Symbol, crate src: FileName, crate module: Item, - crate externs: Vec<(CrateNum, ExternalCrate)>, + crate externs: Vec, crate primitives: ThinVec<(DefId, PrimitiveType)>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. @@ -133,14 +133,14 @@ crate struct TraitWithExtraInfo { crate is_notable: bool, } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] crate struct ExternalCrate { crate crate_num: CrateNum, } impl ExternalCrate { #[inline] - fn def_id(&self) -> DefId { + crate fn def_id(&self) -> DefId { DefId { krate: self.crate_num, index: CRATE_DEF_INDEX } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 7ae602c8033f8..8896f70a317dd 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,9 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, - Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, - Visibility, + inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, + ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, + TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -35,11 +35,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { - externs.push((cnum, cnum.clean(cx))); + externs.push(ExternalCrate { crate_num: cnum }); // Analyze doc-reachability for extern items LibEmbargoVisitor::new(cx).visit_lib(cnum); } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + externs.sort_unstable(); // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e7d6e5ac2c24b..5ea2cdc2ad909 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -151,19 +151,18 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &(n, ref e) in &krate.externs { + for &e in &krate.externs { let name = e.name(tcx); let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); - let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.extern_locations.insert(n, e.location(extern_url, &dst, tcx)); - self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); + self.extern_locations.insert(e.crate_num, e.location(extern_url, &dst, tcx)); + self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. // // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. - for &(_, ref e) in krate.externs.iter().rev() { + for &e in krate.externs.iter().rev() { for &(def_id, prim) in &e.primitives(tcx) { self.primitive_locations.insert(prim, def_id); } From a30fa08928426ee6f78a4f984a379dbfb57c4096 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 5 Jul 2021 12:36:32 -0400 Subject: [PATCH 09/52] Remove trival `impl Clean for CrateNum` --- src/librustdoc/clean/mod.rs | 8 +------- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/clean/utils.rs | 4 ++-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80aaae1580114..1a2852dc6c724 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -14,7 +14,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::middle::resolve_lifetime as rl; @@ -85,12 +85,6 @@ impl, U> Clean> for Option { } } -impl Clean for CrateNum { - fn clean(&self, _cx: &mut DocContext<'_>) -> ExternalCrate { - ExternalCrate { crate_num: *self } - } -} - impl Clean for doctree::Module<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Item { let mut items: Vec = vec![]; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1d3a8c7a8b334..b455d2318e43b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -133,7 +133,7 @@ crate struct TraitWithExtraInfo { crate is_notable: bool, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug)] crate struct ExternalCrate { crate crate_num: CrateNum, } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 8896f70a317dd..5e222d8f9a5fd 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -39,7 +39,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { // Analyze doc-reachability for extern items LibEmbargoVisitor::new(cx).visit_lib(cnum); } - externs.sort_unstable(); + externs.sort_unstable_by_key(|e| e.crate_num); // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. @@ -61,7 +61,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { _ => unreachable!(), } - let local_crate = LOCAL_CRATE.clean(cx); + let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; let src = local_crate.src(cx.tcx); let name = local_crate.name(cx.tcx); let primitives = local_crate.primitives(cx.tcx); From 7c98b3cfe30d3c4e3ba6ad27bc711819e34382d6 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Thu, 8 Jul 2021 16:50:29 +0100 Subject: [PATCH 10/52] Keep metadata when using gc-sections with profile-generate. When building with profile-generate request that metadata is kept during the gc_sections call, as this can sometimes strip out profile data. This missing information in the prof files can then result in missing functions when using the profile information. --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 59447e9de1350..c9a0ef841bbbe 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1931,7 +1931,12 @@ fn add_order_independent_options( // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.link_dead_code() { - let keep_metadata = crate_type == CrateType::Dylib; + // If PGO is enabled sometimes gc_sections will remove the profile data section + // as it appears to be unused. This can then cause the PGO profile file to lose + // some functions. If we are generating a profile we shouldn't strip those metadata + // sections to ensure we have all the data for PGO. + let keep_metadata = + crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled(); cmd.gc_sections(keep_metadata); } From dc639c944af8a47c5017317eebe2764087c8f776 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Wed, 14 Jul 2021 15:34:28 +0200 Subject: [PATCH 11/52] Warn about useless assignments of variables/fields to themselves --- compiler/rustc_passes/src/dead.rs | 54 +++++++++++++++++++ src/test/ui/issues/issue-3290.rs | 1 + src/test/ui/lint/dead-code/self-assign.rs | 50 +++++++++++++++++ src/test/ui/lint/dead-code/self-assign.stderr | 44 +++++++++++++++ .../ui/nll/issue-50461-used-mut-from-moves.rs | 1 + src/test/ui/self/self-re-assign.rs | 1 + 6 files changed, 151 insertions(+) create mode 100644 src/test/ui/lint/dead-code/self-assign.rs create mode 100644 src/test/ui/lint/dead-code/self-assign.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bef56bbc2875f..713d572b93a0b 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -150,6 +150,59 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) { + fn check_for_self_assign_helper( + tcx: TyCtxt<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + lhs: &'tcx hir::Expr<'tcx>, + rhs: &'tcx hir::Expr<'tcx>, + ) -> bool { + match (&lhs.kind, &rhs.kind) { + (hir::ExprKind::Path(ref qpath_l), hir::ExprKind::Path(ref qpath_r)) => { + if let (Res::Local(id_l), Res::Local(id_r)) = ( + typeck_results.qpath_res(qpath_l, lhs.hir_id), + typeck_results.qpath_res(qpath_r, rhs.hir_id), + ) { + if id_l == id_r { + return true; + } + } + return false; + } + (hir::ExprKind::Field(lhs_l, ident_l), hir::ExprKind::Field(lhs_r, ident_r)) => { + if ident_l == ident_r { + return check_for_self_assign_helper(tcx, typeck_results, lhs_l, lhs_r); + } + return false; + } + _ => { + return false; + } + } + } + + if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind { + if check_for_self_assign_helper(self.tcx, self.typeck_results(), lhs, rhs) + && !assign.span.from_expansion() + { + let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); + self.tcx.struct_span_lint_hir( + lint::builtin::DEAD_CODE, + assign.hir_id, + assign.span, + |lint| { + lint.build(&format!( + "useless assignment of {} of type `{}` to itself", + if is_field_assign { "field" } else { "variable" }, + self.typeck_results().expr_ty(lhs), + )) + .emit(); + }, + ) + } + } + } + fn handle_field_pattern_match( &mut self, lhs: &hir::Pat<'_>, @@ -287,6 +340,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } hir::ExprKind::Assign(ref left, ref right, ..) => { self.handle_assign(left); + self.check_for_self_assign(expr); self.visit_expr(right); return; } diff --git a/src/test/ui/issues/issue-3290.rs b/src/test/ui/issues/issue-3290.rs index 63e1b28a60a1e..840c7ff8355d0 100644 --- a/src/test/ui/issues/issue-3290.rs +++ b/src/test/ui/issues/issue-3290.rs @@ -1,5 +1,6 @@ // run-pass #![feature(box_syntax)] +#![allow(dead_code)] pub fn main() { let mut x: Box<_> = box 3; diff --git a/src/test/ui/lint/dead-code/self-assign.rs b/src/test/ui/lint/dead-code/self-assign.rs new file mode 100644 index 0000000000000..b8bf7d860c415 --- /dev/null +++ b/src/test/ui/lint/dead-code/self-assign.rs @@ -0,0 +1,50 @@ +// Test that dead code warnings are issued for superfluous assignments of +// fields or variables to themselves (issue #75356). + +// check-pass +#![allow(unused_assignments)] +#![warn(dead_code)] + +fn main() { + let mut x = 0; + x = x; + //~^ WARNING: useless assignment of variable of type `i32` to itself + + x = (x); + //~^ WARNING: useless assignment of variable of type `i32` to itself + + x = {x}; + // block expressions don't count as self-assignments + + + struct S<'a> { f: &'a str } + let mut s = S { f: "abc" }; + s = s; + //~^ WARNING: useless assignment of variable of type `S` to itself + + s.f = s.f; + //~^ WARNING: useless assignment of field of type `&str` to itself + + + struct N0 { x: Box } + struct N1 { n: N0 } + struct N2(N1); + struct N3 { n: N2 }; + let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) }; + n3.n.0.n.x = n3.n.0.n.x; + //~^ WARNING: useless assignment of field of type `Box` to itself + + let mut t = (1, ((2, 3, (4, 5)),)); + t.1.0.2.1 = t.1.0.2.1; + //~^ WARNING: useless assignment of field of type `i32` to itself + + + let mut y = 0; + macro_rules! assign_to_y { + ($cur:expr) => {{ + y = $cur; + }}; + } + assign_to_y!(y); + // self-assignments in macro expansions are not reported either +} diff --git a/src/test/ui/lint/dead-code/self-assign.stderr b/src/test/ui/lint/dead-code/self-assign.stderr new file mode 100644 index 0000000000000..bb79c0ec72a34 --- /dev/null +++ b/src/test/ui/lint/dead-code/self-assign.stderr @@ -0,0 +1,44 @@ +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:10:5 + | +LL | x = x; + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/self-assign.rs:6:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:13:5 + | +LL | x = (x); + | ^^^^^^^ + +warning: useless assignment of variable of type `S` to itself + --> $DIR/self-assign.rs:22:5 + | +LL | s = s; + | ^^^^^ + +warning: useless assignment of field of type `&str` to itself + --> $DIR/self-assign.rs:25:5 + | +LL | s.f = s.f; + | ^^^^^^^^^ + +warning: useless assignment of field of type `Box` to itself + --> $DIR/self-assign.rs:34:5 + | +LL | n3.n.0.n.x = n3.n.0.n.x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: useless assignment of field of type `i32` to itself + --> $DIR/self-assign.rs:38:5 + | +LL | t.1.0.2.1 = t.1.0.2.1; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: 6 warnings emitted + diff --git a/src/test/ui/nll/issue-50461-used-mut-from-moves.rs b/src/test/ui/nll/issue-50461-used-mut-from-moves.rs index 69d7cdd83a6a1..2458b171e6458 100644 --- a/src/test/ui/nll/issue-50461-used-mut-from-moves.rs +++ b/src/test/ui/nll/issue-50461-used-mut-from-moves.rs @@ -1,6 +1,7 @@ // run-pass #![deny(unused_mut)] +#![allow(dead_code)] struct Foo { pub value: i32 diff --git a/src/test/ui/self/self-re-assign.rs b/src/test/ui/self/self-re-assign.rs index a7b089ebff4c3..88e8614683227 100644 --- a/src/test/ui/self/self-re-assign.rs +++ b/src/test/ui/self/self-re-assign.rs @@ -3,6 +3,7 @@ // that we do not glue_drop before we glue_take (#3290). #![feature(box_syntax)] +#![allow(dead_code)] use std::rc::Rc; From 47ea2ae933f4fda8e069a77f36cb6d8b21d93997 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 24 Jun 2021 21:02:09 +0200 Subject: [PATCH 12/52] Separate encoding paths. The two paths will be modified independently in the next few commits. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 51 +++---- compiler/rustc_metadata/src/rmeta/encoder.rs | 9 +- .../src/ty/query/on_disk_cache.rs | 14 +- compiler/rustc_span/src/hygiene.rs | 139 +++++++++++------- 4 files changed, 116 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d28ebfe107cdd..d39ac588026b0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -30,7 +30,6 @@ use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::Session; -use rustc_span::hygiene::ExpnDataDecodeMode; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; @@ -381,33 +380,29 @@ impl<'a, 'tcx> Decodable> for ExpnId { } }; - rustc_span::hygiene::decode_expn_id( - decoder, - ExpnDataDecodeMode::Metadata(get_ctxt), - |_this, index| { - let cnum = expn_cnum.get().unwrap(); - // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s - // are stored in the owning crate, to avoid duplication. - let crate_data = if cnum == LOCAL_CRATE { - local_cdata - } else { - local_cdata.cstore.get_crate_data(cnum) - }; - let expn_data = crate_data - .root - .expn_data - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - let expn_hash = crate_data - .root - .expn_hashes - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - Ok((expn_data, expn_hash)) - }, - ) + rustc_span::hygiene::decode_expn_id(decoder, get_ctxt, |_this, index| { + let cnum = expn_cnum.get().unwrap(); + // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s + // are stored in the owning crate, to avoid duplication. + let crate_data = if cnum == LOCAL_CRATE { + local_cdata + } else { + local_cdata.cstore.get_crate_data(cnum) + }; + let expn_data = crate_data + .root + .expn_data + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + let expn_hash = crate_data + .root + .expn_hashes + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + Ok((expn_data, expn_hash)) + }) } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5c7d84e2bc97f..ba6d2d74aa7ff 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_session::config::CrateType; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ - hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind}, + hygiene::{HygieneEncodeContext, MacroKind}, RealFileName, }; use rustc_target::abi::VariantIdx; @@ -176,12 +176,7 @@ impl<'a, 'tcx> Encodable> for SyntaxContext { impl<'a, 'tcx> Encodable> for ExpnId { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - rustc_span::hygiene::raw_encode_expn_id( - *self, - &s.hygiene_ctxt, - ExpnDataEncodeMode::Metadata, - s, - ) + rustc_span::hygiene::raw_encode_expn_id(*self, &s.hygiene_ctxt, s) } } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index e3db0d2cf30a6..85e84d6a0f487 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -20,8 +20,7 @@ use rustc_serialize::{ }; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, - SyntaxContext, SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; @@ -793,9 +792,9 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { let expn_data = decoder.expn_data; - rustc_span::hygiene::decode_expn_id( + rustc_span::hygiene::decode_expn_id_incrcomp( decoder, - ExpnDataDecodeMode::incr_comp(decoder.hygiene_context), + decoder.hygiene_context, |this, index| { // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. // We look up the position of the associated `ExpnData` and decode it. @@ -983,12 +982,7 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - rustc_span::hygiene::raw_encode_expn_id( - *self, - s.hygiene_context, - ExpnDataEncodeMode::IncrComp, - s, - ) + rustc_span::hygiene::raw_encode_expn_id_incrcomp(*self, s.hygiene_context, s) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index d292f652896f1..ddf9e7b4255c6 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1076,22 +1076,74 @@ pub struct HygieneDecodeContext { remapped_expns: Lock>>, } -pub fn decode_expn_id<'a, D: Decoder, G>( +pub fn decode_expn_id_incrcomp( d: &mut D, - mode: ExpnDataDecodeMode<'a, G>, + context: &HygieneDecodeContext, decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, -) -> Result -where - G: FnOnce(CrateNum) -> &'a HygieneDecodeContext, -{ +) -> Result { let index = u32::decode(d)?; - let context = match mode { - ExpnDataDecodeMode::IncrComp(context) => context, - ExpnDataDecodeMode::Metadata(get_context) => { - let krate = CrateNum::decode(d)?; - get_context(krate) + + // Do this after decoding, so that we decode a `CrateNum` + // if necessary + if index == ExpnId::root().as_u32() { + debug!("decode_expn_id: deserialized root"); + return Ok(ExpnId::root()); + } + + let outer_expns = &context.remapped_expns; + + // Ensure that the lock() temporary is dropped early + { + if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { + return Ok(expn_id); } - }; + } + + // Don't decode the data inside `HygieneData::with`, since we need to recursively decode + // other ExpnIds + let (mut expn_data, hash) = decode_data(d, index)?; + + let expn_id = HygieneData::with(|hygiene_data| { + if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { + return expn_id; + } + + let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); + + // If we just deserialized an `ExpnData` owned by + // the local crate, its `orig_id` will be stale, + // so we need to update it to its own value. + // This only happens when we deserialize the incremental cache, + // since a crate will never decode its own metadata. + if expn_data.krate == LOCAL_CRATE { + expn_data.orig_id = Some(expn_id.0); + } + + hygiene_data.expn_data.push(Some(expn_data)); + hygiene_data.expn_hashes.push(hash); + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); + + let mut expns = outer_expns.lock(); + let new_len = index as usize + 1; + if expns.len() < new_len { + expns.resize(new_len, None); + } + expns[index as usize] = Some(expn_id); + drop(expns); + expn_id + }); + Ok(expn_id) +} + +pub fn decode_expn_id<'a, D: Decoder>( + d: &mut D, + get_context: impl FnOnce(CrateNum) -> &'a HygieneDecodeContext, + decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, +) -> Result { + let index = u32::decode(d)?; + let krate = CrateNum::decode(d)?; + let context = get_context(krate); // Do this after decoding, so that we decode a `CrateNum` // if necessary @@ -1274,56 +1326,39 @@ pub fn raw_encode_syntax_context( ctxt.0.encode(e) } -pub fn raw_encode_expn_id( +pub fn raw_encode_expn_id_incrcomp( expn: ExpnId, context: &HygieneEncodeContext, - mode: ExpnDataEncodeMode, e: &mut E, ) -> Result<(), E::Error> { // Record the fact that we need to serialize the corresponding // `ExpnData` - let needs_data = || { - if !context.serialized_expns.lock().contains(&expn) { - context.latest_expns.lock().insert(expn); - } - }; - - match mode { - ExpnDataEncodeMode::IncrComp => { - // Always serialize the `ExpnData` in incr comp mode - needs_data(); - expn.0.encode(e) - } - ExpnDataEncodeMode::Metadata => { - let data = expn.expn_data(); - // We only need to serialize the ExpnData - // if it comes from this crate. - // We currently don't serialize any hygiene information data for - // proc-macro crates: see the `SpecializedEncoder` impl - // for crate metadata. - if data.krate == LOCAL_CRATE { - needs_data(); - } - data.orig_id.expect("Missing orig_id").encode(e)?; - data.krate.encode(e) - } + if !context.serialized_expns.lock().contains(&expn) { + context.latest_expns.lock().insert(expn); } + expn.0.encode(e) } -pub enum ExpnDataEncodeMode { - IncrComp, - Metadata, -} - -pub enum ExpnDataDecodeMode<'a, F: FnOnce(CrateNum) -> &'a HygieneDecodeContext> { - IncrComp(&'a HygieneDecodeContext), - Metadata(F), -} - -impl<'a> ExpnDataDecodeMode<'a, Box &'a HygieneDecodeContext>> { - pub fn incr_comp(ctxt: &'a HygieneDecodeContext) -> Self { - ExpnDataDecodeMode::IncrComp(ctxt) +pub fn raw_encode_expn_id( + expn: ExpnId, + context: &HygieneEncodeContext, + e: &mut E, +) -> Result<(), E::Error> { + let data = expn.expn_data(); + // We only need to serialize the ExpnData + // if it comes from this crate. + // We currently don't serialize any hygiene information data for + // proc-macro crates: see the `SpecializedEncoder` impl + // for crate metadata. + if data.krate == LOCAL_CRATE { + // Record the fact that we need to serialize the corresponding + // `ExpnData` + if !context.serialized_expns.lock().contains(&expn) { + context.latest_expns.lock().insert(expn); + } } + data.orig_id.expect("Missing orig_id").encode(e)?; + data.krate.encode(e) } impl Encodable for SyntaxContext { From c2d43e132975126dda1364346db8498fbc3917b0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 10:03:10 +0200 Subject: [PATCH 13/52] Simplify metadata decoding. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 18 +++------- compiler/rustc_span/src/hygiene.rs | 38 +++++--------------- 2 files changed, 12 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d39ac588026b0..e2203fffd45ab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -35,7 +35,6 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; -use std::cell::Cell; use std::io; use std::mem; use std::num::NonZeroUsize; @@ -370,21 +369,12 @@ impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result { let local_cdata = decoder.cdata(); let sess = decoder.sess.unwrap(); - let expn_cnum = Cell::new(None); - let get_ctxt = |cnum| { - expn_cnum.set(Some(cnum)); - if cnum == LOCAL_CRATE { - &local_cdata.hygiene_context - } else { - &local_cdata.cstore.get_crate_data(cnum).cdata.hygiene_context - } - }; - rustc_span::hygiene::decode_expn_id(decoder, get_ctxt, |_this, index| { - let cnum = expn_cnum.get().unwrap(); + rustc_span::hygiene::decode_expn_id(decoder, |cnum, index| { // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s // are stored in the owning crate, to avoid duplication. - let crate_data = if cnum == LOCAL_CRATE { + debug_assert_ne!(cnum, LOCAL_CRATE); + let crate_data = if cnum == local_cdata.cnum { local_cdata } else { local_cdata.cstore.get_crate_data(cnum) @@ -401,7 +391,7 @@ impl<'a, 'tcx> Decodable> for ExpnId { .get(&crate_data, index) .unwrap() .decode((&crate_data, sess)); - Ok((expn_data, expn_hash)) + (expn_data, expn_hash) }) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ddf9e7b4255c6..e3174b47f8d0c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1136,14 +1136,12 @@ pub fn decode_expn_id_incrcomp( Ok(expn_id) } -pub fn decode_expn_id<'a, D: Decoder>( +pub fn decode_expn_id( d: &mut D, - get_context: impl FnOnce(CrateNum) -> &'a HygieneDecodeContext, - decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, + decode_data: impl FnOnce(CrateNum, u32) -> (ExpnData, ExpnHash), ) -> Result { let index = u32::decode(d)?; let krate = CrateNum::decode(d)?; - let context = get_context(krate); // Do this after decoding, so that we decode a `CrateNum` // if necessary @@ -1152,18 +1150,14 @@ pub fn decode_expn_id<'a, D: Decoder>( return Ok(ExpnId::root()); } - let outer_expns = &context.remapped_expns; - - // Ensure that the lock() temporary is dropped early - { - if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { - return Ok(expn_id); - } - } + // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE. + debug_assert_ne!(krate, LOCAL_CRATE); // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds - let (mut expn_data, hash) = decode_data(d, index)?; + let (expn_data, hash) = decode_data(krate, index); + debug_assert_eq!(krate, expn_data.krate); + debug_assert_eq!(expn_data.orig_id, Some(index)); let expn_id = HygieneData::with(|hygiene_data| { if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { @@ -1171,30 +1165,14 @@ pub fn decode_expn_id<'a, D: Decoder>( } let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); - - // If we just deserialized an `ExpnData` owned by - // the local crate, its `orig_id` will be stale, - // so we need to update it to its own value. - // This only happens when we deserialize the incremental cache, - // since a crate will never decode its own metadata. - if expn_data.krate == LOCAL_CRATE { - expn_data.orig_id = Some(expn_id.0); - } - hygiene_data.expn_data.push(Some(expn_data)); hygiene_data.expn_hashes.push(hash); let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); debug_assert!(_old_id.is_none()); - let mut expns = outer_expns.lock(); - let new_len = index as usize + 1; - if expns.len() < new_len { - expns.resize(new_len, None); - } - expns[index as usize] = Some(expn_id); - drop(expns); expn_id }); + Ok(expn_id) } From 1a900042abe4ee9626cd7274816816e9ca691a25 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 15 Jul 2021 23:47:03 +0200 Subject: [PATCH 14/52] Added diagnostic items to functions for Clippy --- compiler/rustc_span/src/symbol.rs | 9 +++++++++ library/core/src/cmp.rs | 2 ++ library/core/src/iter/sources/repeat.rs | 1 + library/core/src/mem/mod.rs | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9051c9d69b5c1..944e896ba6fd5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -368,6 +368,8 @@ symbols! { closure, closure_to_fn_coercion, cmp, + cmp_max, + cmp_min, cmpxchg16b_target_feature, cmse_nonsecure_entry, coerce_unsized, @@ -672,6 +674,7 @@ symbols! { item, item_like_imports, iter, + iter_repeat, keyword, kind, kreg, @@ -738,6 +741,12 @@ symbols! { maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, + mem_discriminant, + mem_drop, + mem_forget, + mem_replace, + mem_size_of, + mem_size_of_val, mem_uninitialized, mem_zeroed, member_constraints, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 879deed3bed5e..79610bb409d37 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1104,6 +1104,7 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] pub fn min(v1: T, v2: T) -> T { v1.min(v2) } @@ -1166,6 +1167,7 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] pub fn max(v1: T, v2: T) -> T { v1.max(v2) } diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index a9478041c69c4..733142ed01103 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -51,6 +51,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "iter_repeat")] pub fn repeat(elt: T) -> Repeat { Repeat { element: elt } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5bf47c3951da2..2c75de39ffa2f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -140,6 +140,7 @@ pub use crate::intrinsics::transmute; #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_forget")] pub const fn forget(t: T) { let _ = ManuallyDrop::new(t); } @@ -298,6 +299,7 @@ pub fn forget_unsized(t: T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_size_of", since = "1.24.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of")] pub const fn size_of() -> usize { intrinsics::size_of::() } @@ -324,6 +326,7 @@ pub const fn size_of() -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer unsafe { intrinsics::size_of_val(val) } @@ -814,6 +817,7 @@ pub fn take(dest: &mut T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] #[rustc_const_unstable(feature = "const_replace", issue = "83164")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] pub const fn replace(dest: &mut T, src: T) -> T { // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and @@ -888,6 +892,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_drop")] pub fn drop(_x: T) {} /// Interprets `src` as having type `&U`, and then reads `src` without moving @@ -1015,6 +1020,7 @@ impl fmt::Debug for Discriminant { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")] pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v)) } From d38f2b0cc1c58392fe9736c468e8943fc6472096 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 15 Jul 2021 23:51:34 +0200 Subject: [PATCH 15/52] Added diagnostic items to structs and traits for Clippy --- compiler/rustc_span/src/symbol.rs | 13 +++++++++++++ library/alloc/src/borrow.rs | 1 + library/alloc/src/collections/btree/map/entry.rs | 1 + library/core/src/any.rs | 1 + library/core/src/convert/mod.rs | 2 ++ library/core/src/iter/traits/double_ended.rs | 1 + library/core/src/time.rs | 1 + library/std/src/collections/hash/map.rs | 1 + library/std/src/fs.rs | 3 +++ library/std/src/io/mod.rs | 2 ++ 10 files changed, 26 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 944e896ba6fd5..fa2afaac37509 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -122,10 +122,14 @@ symbols! { // nice to have. Symbols { Alignment, + Any, Arc, Argument, ArgumentV1, Arguments, + AsMut, + AsRef, + BTreeEntry, BTreeMap, BTreeSet, BinaryHeap, @@ -139,6 +143,7 @@ symbols! { Continue, Copy, Count, + Cow, Debug, DebugStruct, DebugTuple, @@ -146,12 +151,17 @@ symbols! { Decoder, Default, Deref, + DirBuilder, + DoubleEndedIterator, + Duration, Encodable, Encoder, Eq, Equal, Err, Error, + File, + FileType, FormatSpec, Formatter, From, @@ -164,9 +174,12 @@ symbols! { HashMap, HashSet, Hasher, + HashMapEntry, Implied, Input, IntoIterator, + IoRead, + IoWrite, Is, ItemContext, Iterator, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 9d61b3684b82c..482a497201de6 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -177,6 +177,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 6b30d95977395..5fec8dc2d1334 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -14,6 +14,7 @@ use Entry::*; /// /// [`entry`]: BTreeMap::entry #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeEntry")] pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5e1725cfc7a63..19652106b3d01 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -108,6 +108,7 @@ use crate::intrinsics; // unsafe traits and unsafe methods (i.e., `type_id` would still be safe to call, // but we would likely want to indicate as such in documentation). #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Any")] pub trait Any: 'static { /// Gets the `TypeId` of `self`. /// diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 65af8508a6839..1e512af48051e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -152,6 +152,7 @@ pub const fn identity(x: T) -> T { /// is_hello(s); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")] pub trait AsRef { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] @@ -193,6 +194,7 @@ pub trait AsRef { /// /// [`Box`]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")] pub trait AsMut { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 6d3ab788e5f48..9a9cf20077096 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -36,6 +36,7 @@ use crate::ops::{ControlFlow, Try}; /// assert_eq!(None, iter.next_back()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 92a4e60391894..2d8a1cb1ab016 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -61,6 +61,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// crate to do so. #[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index d7cb8a556367c..fac285c96f00d 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1829,6 +1829,7 @@ impl Debug for RawEntryBuilder<'_, K, V, S> { /// /// [`entry`]: HashMap::entry #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMapEntry")] pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a9ce814e2ec18..997b7670ea982 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -88,6 +88,7 @@ use crate::time::SystemTime; /// [`BufReader`]: io::BufReader /// [`sync_all`]: File::sync_all #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "File")] pub struct File { inner: fs_imp::File, } @@ -183,12 +184,14 @@ pub struct Permissions(fs_imp::FilePermissions); /// It is returned by [`Metadata::file_type`] method. #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "FileType")] pub struct FileType(fs_imp::FileType); /// A builder used to create directories in various manners. /// /// This builder also supports platform-specific options. #[stable(feature = "dir_builder", since = "1.6.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DirBuilder")] #[derive(Debug)] pub struct DirBuilder { inner: fs_imp::DirBuilder, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9daeee711adea..714e4cdea0fae 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -514,6 +514,7 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ /// [`File`]: crate::fs::File #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -1361,6 +1362,7 @@ impl Initializer { /// [`write_all`]: Write::write_all #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// From 0d3d6f05f15bcac8a565d7ed0206469c8df6439a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Jul 2021 10:31:56 +0200 Subject: [PATCH 16/52] fix typo in compile_fail doctest --- library/core/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b7af3ea8c1af4..c27db0767ac9d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -356,7 +356,7 @@ //! // must have the same concrete type. //! fn make_iter(do_insert: bool) -> impl Iterator { //! // Explicit returns to illustrate return types not matching -//! match x { +//! match do_insert { //! true => return (0..4).chain(once(42)).chain(4..8), //! false => return (0..4).chain(empty()).chain(4..8), //! } From 774a79e3fd40dee6dcdb80ef57e9e49a6d38d381 Mon Sep 17 00:00:00 2001 From: oxalica Date: Sat, 17 Jul 2021 00:19:44 +0800 Subject: [PATCH 17/52] Mark `Option::insert` as must_use --- library/core/src/option.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b7af3ea8c1af4..d130854911322 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1179,6 +1179,7 @@ impl Option { /// *val = 3; /// assert_eq!(opt.unwrap(), 3); /// ``` + #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] pub fn insert(&mut self, value: T) -> &mut T { From ce59f1aac53ba209d0a97af720f596f943fcfbaa Mon Sep 17 00:00:00 2001 From: Richard Cobbe Date: Mon, 12 Jul 2021 12:46:27 -0700 Subject: [PATCH 18/52] Consider all fields when comparing DllImports, to remove nondetermininsm in multiple-definitions test --- compiler/rustc_codegen_cranelift/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_ssa/src/back/link.rs | 114 ++++++++---------- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/middle/cstore.rs | 6 +- .../multiple-declarations.rs | 19 +++ .../multiple-declarations.stderr | 17 +++ 7 files changed, 91 insertions(+), 75 deletions(-) create mode 100644 src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index cb1cb3c74dbb5..e32dae49131ab 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -221,9 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend { sess, &codegen_results, outputs, - ); - - Ok(()) + ) } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 26fd1cfbcd08e..aa4db1622b233 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -292,9 +292,7 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary::>(sess, &codegen_results, outputs); - - Ok(()) + link_binary::>(sess, &codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f9efa448c93fa..773a1c500b2f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,9 +1,9 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::Handler; +use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; +use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -35,7 +35,6 @@ use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, Se use tempfile::Builder as TempFileBuilder; use std::ffi::OsString; -use std::iter::FromIterator; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -54,7 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, outputs: &OutputFilenames, -) { +) -> Result<(), ErrorReported> { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types().iter() { @@ -95,11 +94,17 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); - link_rlib::(sess, codegen_results, RlibFlavor::Normal, &out_filename, &path) - .build(); + link_rlib::( + sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &path, + )? + .build(); } CrateType::Staticlib => { - link_staticlib::(sess, codegen_results, &out_filename, &path); + link_staticlib::(sess, codegen_results, &out_filename, &path)?; } _ => { link_natively::( @@ -145,6 +150,8 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( } } }); + + Ok(()) } pub fn each_linked_rlib( @@ -220,7 +227,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( flavor: RlibFlavor, out_filename: &Path, tmpdir: &MaybeTempDir, -) -> B { +) -> Result { info!("preparing rlib to {:?}", out_filename); let mut ab = ::new(sess, out_filename, None); @@ -259,7 +266,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries) + collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); } @@ -312,7 +319,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } } - return ab; + return Ok(ab); // For rlibs we "pack" rustc metadata into a dummy object file. When rustc // creates a dylib crate type it will pass `--whole-archive` (or the @@ -454,65 +461,40 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( fn collate_raw_dylibs( sess: &Session, used_libraries: &[NativeLib], -) -> Vec<(String, Vec)> { - let mut dylib_table: FxHashMap> = FxHashMap::default(); +) -> Result)>, ErrorReported> { + // Use index maps to preserve original order of imports and libraries. + let mut dylib_table = FxIndexMap::>::default(); for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { - let name = lib.name.unwrap_or_else(|| - bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier") - ); - let name = if matches!(lib.verbatim, Some(true)) { - name.to_string() - } else { - format!("{}.dll", name) - }; - dylib_table.entry(name).or_default().extend(lib.dll_imports.iter().cloned()); - } - } - - // Rustc already signals an error if we have two imports with the same name but different - // calling conventions (or function signatures), so we don't have pay attention to those - // when ordering. - // FIXME: when we add support for ordinals, figure out if we need to do anything if we - // have two DllImport values with the same name but different ordinals. - let mut result: Vec<(String, Vec)> = dylib_table - .into_iter() - .map(|(lib_name, import_table)| { - let mut imports = Vec::from_iter(import_table.into_iter()); - imports.sort_unstable_by_key(|x: &DllImport| x.name.as_str()); - (lib_name, imports) - }) - .collect::>(); - result.sort_unstable_by(|a: &(String, Vec), b: &(String, Vec)| { - a.0.cmp(&b.0) - }); - let result = result; - - // Check for multiple imports with the same name but different calling conventions or - // (when relevant) argument list sizes. Rustc only signals an error for this if the - // declarations are at the same scope level; if one shadows the other, we only get a lint - // warning. - for (library, imports) in &result { - let mut import_table: FxHashMap = FxHashMap::default(); - for import in imports { - if let Some(old_convention) = - import_table.insert(import.name, import.calling_convention) - { - if import.calling_convention != old_convention { - sess.span_fatal( - import.span, - &format!( - "multiple definitions of external function `{}` from library `{}` have different calling conventions", - import.name, - library, - )); + let ext = if matches!(lib.verbatim, Some(true)) { "" } else { ".dll" }; + let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); + let imports = dylib_table.entry(name.clone()).or_default(); + for import in &lib.dll_imports { + if let Some(old_import) = imports.insert(import.name, import) { + // FIXME: when we add support for ordinals, figure out if we need to do anything + // if we have two DllImport values with the same name but different ordinals. + if import.calling_convention != old_import.calling_convention { + sess.span_err( + import.span, + &format!( + "multiple declarations of external function `{}` from \ + library `{}` have different calling conventions", + import.name, name, + ), + ); + } } } } } - - result + sess.compile_status()?; + Ok(dylib_table + .into_iter() + .map(|(name, imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + }) + .collect()) } /// Create a static archive. @@ -531,9 +513,9 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( codegen_results: &CodegenResults, out_filename: &Path, tempdir: &MaybeTempDir, -) { +) -> Result<(), ErrorReported> { let mut ab = - link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir); + link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir)?; let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { @@ -581,6 +563,8 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( print_native_static_libs(sess, &all_native_libs); } } + + Ok(()) } fn escape_stdout_stderr_string(s: &[u8]) -> String { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0e924d644353c..04a1f39663c6f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1569,7 +1569,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); - self.lazy(used_libraries.iter().cloned()) + self.lazy(used_libraries.iter()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index fcd4988635b07..61bc2d6012410 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -66,7 +66,7 @@ pub enum LinkagePreference { RequireStatic, } -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +#[derive(Debug, Encodable, Decodable, HashStable)] pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, @@ -77,7 +77,7 @@ pub struct NativeLib { pub dll_imports: Vec, } -#[derive(Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] pub struct DllImport { pub name: Symbol, pub ordinal: Option, @@ -94,7 +94,7 @@ pub struct DllImport { /// /// The usize value, where present, indicates the size of the function's argument list /// in bytes. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)] pub enum DllCallingConvention { C, Stdcall(usize), diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs new file mode 100644 index 0000000000000..d02bebc9d61d2 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs @@ -0,0 +1,19 @@ +// only-i686-pc-windows-msvc +// compile-flags: --crate-type lib --emit link +#![allow(clashing_extern_declarations)] +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + #[link(name = "foo", kind = "raw-dylib")] + extern "stdcall" { + fn f(x: i32); + //~^ ERROR multiple declarations of external function `f` from library `foo.dll` have different calling conventions + } + + unsafe { f(42); } +} diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr new file mode 100644 index 0000000000000..a9cfd6b23f9f8 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multiple-declarations.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions + --> $DIR/multiple-declarations.rs:14:9 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + From 9b874c400388a2158b6575e139752b3d0a27645b Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 3 Jul 2021 17:56:09 +0200 Subject: [PATCH 19/52] Check that const parameters of trait methods have compatible types --- .../rustc_typeck/src/check/compare_method.rs | 66 +++++++++++++++++++ src/test/ui/const-generics/issue-86820.rs | 25 +++++++ src/test/ui/const-generics/issue-86820.stderr | 15 +++++ 3 files changed, 106 insertions(+) create mode 100644 src/test/ui/const-generics/issue-86820.rs create mode 100644 src/test/ui/const-generics/issue-86820.stderr diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 12d0c14a3d51a..d35868881558e 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>( { return; } + + if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) { + return; + } } fn compare_predicate_entailment<'tcx>( @@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>( if error_found { Err(ErrorReported) } else { Ok(()) } } +fn compare_const_param_types<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + trait_m: &ty::AssocItem, + trait_item_span: Option, +) -> Result<(), ErrorReported> { + let const_params_of = |def_id| { + tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind { + GenericParamDefKind::Const { .. } => Some(param.def_id), + _ => None, + }) + }; + let const_params_impl = const_params_of(impl_m.def_id); + let const_params_trait = const_params_of(trait_m.def_id); + + for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) { + let impl_ty = tcx.type_of(const_param_impl); + let trait_ty = tcx.type_of(const_param_trait); + if impl_ty != trait_ty { + let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) { + Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => ( + span, + match name { + hir::ParamName::Plain(ident) => Some(ident), + _ => None, + }, + ), + other => bug!( + "expected GenericParam, found {:?}", + other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n)) + ), + }; + let trait_span = match tcx.hir().get_if_local(const_param_trait) { + Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span), + _ => None, + }; + let mut err = struct_span_err!( + tcx.sess, + *impl_span, + E0053, + "method `{}` has an incompatible const parameter type for trait", + trait_m.ident + ); + err.span_note( + trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span), + &format!( + "the const parameter{} has type `{}`, but the declaration \ + in trait `{}` has type `{}`", + &impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{}`", ident)), + impl_ty, + tcx.def_path_str(trait_m.def_id), + trait_ty + ), + ); + err.emit(); + return Err(ErrorReported); + } + } + + Ok(()) +} + crate fn compare_const_impl<'tcx>( tcx: TyCtxt<'tcx>, impl_c: &ty::AssocItem, diff --git a/src/test/ui/const-generics/issue-86820.rs b/src/test/ui/const-generics/issue-86820.rs new file mode 100644 index 0000000000000..04650403c6baf --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.rs @@ -0,0 +1,25 @@ +// Regression test for the ICE described in #86820. + +#![allow(unused,dead_code)] +use std::ops::BitAnd; + +const C: fn() = || is_set(); +fn is_set() { + 0xffu8.bit::<0>(); +} + +trait Bits { + fn bit(self) -> bool; + //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` +} + +impl Bits for u8 { + fn bit(self) -> bool { + //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053] + let i = 1 << I; + let mask = u8::from(i); + mask & self == mask + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-86820.stderr b/src/test/ui/const-generics/issue-86820.stderr new file mode 100644 index 0000000000000..f4396f2f2b0a2 --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `bit` has an incompatible const parameter type for trait + --> $DIR/issue-86820.rs:17:18 + | +LL | fn bit(self) -> bool { + | ^ + | +note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` + --> $DIR/issue-86820.rs:12:18 + | +LL | fn bit(self) -> bool; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. From 6ffb6c46c760cf93bbccb7ae4c7c9c1a6cc5d8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Jul 2021 00:42:53 +0200 Subject: [PATCH 20/52] rustc_middle: remove redundant clone found while looking through some clippy lint warnings --- compiler/rustc_middle/src/ty/closure.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index b0156daf17eff..6b51adc6aafdd 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -281,11 +281,10 @@ pub struct CaptureInfo<'tcx> { } pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { - let name = match place.base { + let mut curr_string: String = match place.base { HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(), _ => bug!("Capture_information should only contain upvars"), }; - let mut curr_string = name; for (i, proj) in place.projections.iter().enumerate() { match proj.kind { @@ -314,7 +313,7 @@ pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> } } - curr_string.to_string() + curr_string } #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] From 67002db2cf78f68ff140d32847e41effae9e9408 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 17 Jul 2021 12:20:43 +0200 Subject: [PATCH 21/52] Corrected symbol order after adding diagnostic items --- compiler/rustc_span/src/symbol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fa2afaac37509..ed2f8a0f35112 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -172,9 +172,9 @@ symbols! { GlobalAlloc, Hash, HashMap, + HashMapEntry, HashSet, Hasher, - HashMapEntry, Implied, Input, IntoIterator, From 6e78d6c9d697217998322ab626cbeee24cdfe228 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 10 Jul 2021 23:34:41 +0200 Subject: [PATCH 22/52] Make the CrateNum part of the ExpnId. --- compiler/rustc_ast/src/node_id.rs | 6 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 9 +- .../src/rmeta/decoder/cstore_impl.rs | 19 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 14 +- compiler/rustc_metadata/src/rmeta/mod.rs | 6 +- compiler/rustc_middle/src/middle/cstore.rs | 6 +- .../src/ty/query/on_disk_cache.rs | 12 +- compiler/rustc_span/src/hygiene.rs | 345 +++++++++++++----- compiler/rustc_span/src/lib.rs | 2 +- 9 files changed, 307 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index d20bace608882..e1e7d757d7e62 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -1,4 +1,4 @@ -use rustc_span::ExpnId; +use rustc_span::{ExpnId, LocalExpnId}; use std::fmt; rustc_index::newtype_index! { @@ -25,11 +25,11 @@ pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; impl NodeId { pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self { - NodeId::from_u32(expn_id.as_u32()) + NodeId::from_u32(expn_id.expect_local().as_u32()) } pub fn placeholder_to_expn_id(self) -> ExpnId { - ExpnId::from_u32(self.as_u32()) + LocalExpnId::from_u32(self.as_u32()).to_expn_id() } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e2203fffd45ab..4b72ac8695794 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -30,9 +30,10 @@ use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::Session; +use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; use std::io; @@ -348,6 +349,12 @@ impl<'a, 'tcx> Decodable> for DefIndex { } } +impl<'a, 'tcx> Decodable> for ExpnIndex { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { + Ok(ExpnIndex::from_u32(d.read_u32()?)) + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result { let cdata = decoder.cdata(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ce8dfeae076e6..67023e9e84e22 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,11 +18,11 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; +use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; -use rustc_span::ExpnId; use smallvec::SmallVec; use std::any::Any; @@ -494,6 +494,23 @@ impl CrateStore for CStore { fn as_any(&self) -> &dyn Any { self } + fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash) { + let crate_data = self.get_crate_data(expn_id.krate); + ( + crate_data + .root + .expn_data + .get(&crate_data, expn_id.local_id) + .unwrap() + .decode((&crate_data, sess)), + crate_data + .root + .expn_hashes + .get(&crate_data, expn_id.local_id) + .unwrap() + .decode((&crate_data, sess)), + ) + } fn crate_name(&self, cnum: CrateNum) -> Symbol { self.get_crate_data(cnum).root.name diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ba6d2d74aa7ff..4684daef4a18c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_session::config::CrateType; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ - hygiene::{HygieneEncodeContext, MacroKind}, + hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}, RealFileName, }; use rustc_target::abi::VariantIdx; @@ -168,6 +168,12 @@ impl<'a, 'tcx> Encodable> for DefIndex { } } +impl<'a, 'tcx> Encodable> for ExpnIndex { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + s.emit_u32(self.as_u32()) + } +} + impl<'a, 'tcx> Encodable> for SyntaxContext { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s) @@ -1588,8 +1594,10 @@ impl EncodeContext<'a, 'tcx> { Ok(()) }, |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { - expn_data_table.set(index, this.lazy(expn_data)); - expn_hash_table.set(index, this.lazy(hash)); + if let Some(index) = index.as_local() { + expn_data_table.set(index.as_raw(), this.lazy(expn_data)); + expn_hash_table.set(index.as_raw(), this.lazy(hash)); + } Ok(()) }, ); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f2ebfb9b725ba..a487753f4628a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_span::edition::Edition; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -170,8 +170,8 @@ macro_rules! Lazy { } type SyntaxContextTable = Lazy>>; -type ExpnDataTable = Lazy>>; -type ExpnHashTable = Lazy>>; +type ExpnDataTable = Lazy>>; +type ExpnHashTable = Lazy>>; #[derive(MetadataEncodable, MetadataDecodable)] crate struct ProcMacroData { diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 7efe8e061e885..c10fcc2e90c7e 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -6,12 +6,13 @@ use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::sync::{self, MetadataRef}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; -use rustc_session::StableCrateId; +use rustc_session::Session; +use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::Target; @@ -187,6 +188,7 @@ pub type MetadataLoaderDyn = dyn MetadataLoader + Sync; /// during resolve) pub trait CrateStore: std::fmt::Debug { fn as_any(&self) -> &dyn Any; + fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash); // Foreign definitions. // This information is safe to access, since it's hashed as part of the DefPathHash, which incr. diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 85e84d6a0f487..358d016368ee0 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -364,9 +364,12 @@ impl<'sess> OnDiskCache<'sess> { Ok(()) }, |encoder, index, expn_data, hash| -> FileEncodeResult { - let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?; - expn_ids.insert(index, pos); + if index.krate == LOCAL_CRATE { + let pos = AbsoluteBytePos::new(encoder.position()); + encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?; + expn_ids.insert(index.local_id.as_u32(), pos); + } + // TODO Handle foreign expansions. Ok(()) }, )?; @@ -807,6 +810,9 @@ impl<'a, 'tcx> Decodable> for ExpnId { Ok(data) }) }, + |this, expn_id| { + Ok(this.tcx.untracked_resolutions.cstore.decode_expn_data(this.tcx.sess, expn_id)) + }, ) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e3174b47f8d0c..14b6811298261 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -29,12 +29,13 @@ use crate::symbol::{kw, sym, Symbol}; use crate::with_session_globals; use crate::{HashStableContext, Span, DUMMY_SP}; -use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::def_id::{CrateNum, DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::unhash::UnhashMap; +use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; @@ -58,9 +59,34 @@ pub struct SyntaxContextData { dollar_crate_name: Symbol, } +rustc_index::newtype_index! { + /// A unique ID associated with a macro invocation and expansion. + pub struct ExpnIndex { + ENCODABLE = custom + } +} + /// A unique ID associated with a macro invocation and expansion. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct ExpnId(u32); +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct ExpnId { + pub krate: CrateNum, + pub local_id: ExpnIndex, +} + +impl fmt::Debug for ExpnId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Generate crate_::{{expn_}}. + write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.private) + } +} + +rustc_index::newtype_index! { + /// A unique ID associated with a macro invocation and expansion. + pub struct LocalExpnId { + ENCODABLE = custom + DEBUG_FORMAT = "expn{}" + } +} /// A unique hash value associated to an expansion. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] @@ -86,31 +112,103 @@ pub enum Transparency { Opaque, } -impl ExpnId { - pub fn fresh_empty() -> Self { +impl LocalExpnId { + /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. + pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0); + + pub fn from_raw(idx: ExpnIndex) -> LocalExpnId { + LocalExpnId::from_u32(idx.as_u32()) + } + + pub fn as_raw(self) -> ExpnIndex { + ExpnIndex::from_u32(self.as_u32()) + } + + pub fn fresh_empty() -> LocalExpnId { HygieneData::with(|data| data.fresh_expn(None)) } - pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> Self { + pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId { + debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data))); update_disambiguator(expn_id, ctx); expn_id } - /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. #[inline] - pub fn root() -> Self { - ExpnId(0) + pub fn expn_hash(self) -> ExpnHash { + HygieneData::with(|data| data.local_expn_hash(self)) } #[inline] - pub fn as_u32(self) -> u32 { - self.0 + pub fn expn_data(self) -> ExpnData { + HygieneData::with(|data| data.local_expn_data(self).clone()) + } + + #[inline] + pub fn to_expn_id(self) -> ExpnId { + ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() } + } + + #[inline] + pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { + debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); + HygieneData::with(|data| { + let old_expn_data = &mut data.local_expn_data[self]; + assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); + assert_eq!(expn_data.orig_id, None); + debug_assert_eq!(expn_data.krate, LOCAL_CRATE); + expn_data.orig_id = Some(self.as_u32()); + *old_expn_data = Some(expn_data); + }); + update_disambiguator(self, ctx) + } + + #[inline] + pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool { + self.to_expn_id().is_descendant_of(ancestor.to_expn_id()) } + /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than + /// `expn_id.is_descendant_of(ctxt.outer_expn())`. #[inline] - pub fn from_u32(raw: u32) -> ExpnId { - ExpnId(raw) + pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { + self.to_expn_id().outer_expn_is_descendant_of(ctxt) + } + + /// Returns span for the macro which originally caused this expansion to happen. + /// + /// Stops backtracing at include! boundary. + #[inline] + pub fn expansion_cause(self) -> Option { + self.to_expn_id().expansion_cause() + } + + #[inline] + #[track_caller] + pub fn parent(self) -> LocalExpnId { + self.expn_data().parent.as_local().unwrap() + } +} + +impl ExpnId { + /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. + /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0. + pub const fn root() -> ExpnId { + ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) } + } + + pub fn fresh_empty() -> ExpnId { + LocalExpnId::fresh_empty().to_expn_id() + } + + pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> ExpnId { + LocalExpnId::fresh(expn_data, ctx).to_expn_id() + } + + #[inline] + pub fn set_expn_data(self, expn_data: ExpnData, ctx: impl HashStableContext) { + self.expect_local().set_expn_data(expn_data, ctx) } #[inline] @@ -124,20 +222,19 @@ impl ExpnId { } #[inline] - pub fn expn_data(self) -> ExpnData { - HygieneData::with(|data| data.expn_data(self).clone()) + pub fn as_local(self) -> Option { + if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None } } #[inline] - pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { - HygieneData::with(|data| { - let old_expn_data = &mut data.expn_data[self.0 as usize]; - assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); - assert_eq!(expn_data.orig_id, None); - expn_data.orig_id = Some(self.as_u32()); - *old_expn_data = Some(expn_data); - }); - update_disambiguator(self, ctx) + #[track_caller] + pub fn expect_local(self) -> LocalExpnId { + self.as_local().unwrap() + } + + #[inline] + pub fn expn_data(self) -> ExpnData { + HygieneData::with(|data| data.expn_data(self).clone()) } pub fn is_descendant_of(self, ancestor: ExpnId) -> bool { @@ -175,8 +272,10 @@ pub struct HygieneData { /// Each expansion should have an associated expansion data, but sometimes there's a delay /// between creation of an expansion ID and obtaining its data (e.g. macros are collected /// first and then resolved later), so we use an `Option` here. - expn_data: Vec>, - expn_hashes: Vec, + local_expn_data: IndexVec>, + local_expn_hashes: IndexVec, + foreign_expn_data: FxHashMap, + foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, syntax_context_data: Vec, syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, @@ -194,15 +293,17 @@ impl HygieneData { ExpnKind::Root, DUMMY_SP, edition, - Some(DefId::local(CRATE_DEF_INDEX)), + Some(CRATE_DEF_ID.to_def_id()), None, ); root_data.orig_id = Some(0); HygieneData { - expn_data: vec![Some(root_data)], - expn_hashes: vec![ExpnHash(Fingerprint::ZERO)], - expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId(0))) + local_expn_data: IndexVec::from_elem_n(Some(root_data), 1), + local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1), + foreign_expn_data: FxHashMap::default(), + foreign_expn_hashes: FxHashMap::default(), + expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), syntax_context_data: vec![SyntaxContextData { outer_expn: ExpnId::root(), @@ -221,24 +322,42 @@ impl HygieneData { with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) } - fn fresh_expn(&mut self, mut expn_data: Option) -> ExpnId { - let raw_id = self.expn_data.len() as u32; + fn fresh_expn(&mut self, mut expn_data: Option) -> LocalExpnId { + let expn_id = self.local_expn_data.next_index(); if let Some(data) = expn_data.as_mut() { + debug_assert_eq!(data.krate, LOCAL_CRATE); assert_eq!(data.orig_id, None); - data.orig_id = Some(raw_id); + data.orig_id = Some(expn_id.as_u32()); } - self.expn_data.push(expn_data); - self.expn_hashes.push(ExpnHash(Fingerprint::ZERO)); - ExpnId(raw_id) + self.local_expn_data.push(expn_data); + let _eid = self.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); + debug_assert_eq!(expn_id, _eid); + expn_id + } + + #[inline] + fn local_expn_hash(&self, expn_id: LocalExpnId) -> ExpnHash { + self.local_expn_hashes[expn_id] } #[inline] fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash { - self.expn_hashes[expn_id.0 as usize] + match expn_id.as_local() { + Some(expn_id) => self.local_expn_hashes[expn_id], + None => self.foreign_expn_hashes[&expn_id], + } + } + + fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData { + self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") } fn expn_data(&self, expn_id: ExpnId) -> &ExpnData { - self.expn_data[expn_id.0 as usize].as_ref().expect("no expansion data for an expansion ID") + if let Some(expn_id) = expn_id.as_local() { + self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") + } else { + &self.foreign_expn_data[&expn_id] + } } fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool { @@ -453,17 +572,21 @@ pub fn debug_hygiene_data(verbose: bool) -> String { } else { let mut s = String::from(""); s.push_str("Expansions:"); - data.expn_data.iter().enumerate().for_each(|(id, expn_info)| { - let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); + let mut debug_expn_data = |(id, expn_info): (&ExpnId, &ExpnData)| { s.push_str(&format!( - "\n{}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", + "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", id, expn_info.parent, expn_info.call_site.ctxt(), expn_info.def_site.ctxt(), expn_info.kind, - )); + )) + }; + data.local_expn_data.iter_enumerated().for_each(|(id, expn_info)| { + let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); + debug_expn_data((&id.to_expn_id(), expn_info)) }); + data.foreign_expn_data.iter().for_each(debug_expn_data); s.push_str("\n\nSyntaxContexts:"); data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { s.push_str(&format!( @@ -1024,7 +1147,7 @@ impl HygieneEncodeContext { &self, encoder: &mut T, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>, - mut encode_expn: impl FnMut(&mut T, u32, ExpnData, ExpnHash) -> Result<(), R>, + mut encode_expn: impl FnMut(&mut T, ExpnId, ExpnData, ExpnHash) -> Result<(), R>, ) -> Result<(), R> { // When we serialize a `SyntaxContextData`, we may end up serializing // a `SyntaxContext` that we haven't seen before @@ -1051,9 +1174,9 @@ impl HygieneEncodeContext { let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) }; - for_all_expns_in(latest_expns.into_iter(), |index, expn, data, hash| { + for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| { if self.serialized_expns.lock().insert(expn) { - encode_expn(encoder, index, data, hash)?; + encode_expn(encoder, expn, data, hash)?; } Ok(()) })?; @@ -1073,56 +1196,75 @@ pub struct HygieneDecodeContext { // `SyntaxContext` remapped_ctxts: Lock>>, // The same as `remapepd_ctxts`, but for `ExpnId`s - remapped_expns: Lock>>, + remapped_expns: Lock>>, } pub fn decode_expn_id_incrcomp( d: &mut D, context: &HygieneDecodeContext, decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, + decode_foreign: impl FnOnce(&mut D, ExpnId) -> Result<(ExpnData, ExpnHash), D::Error>, ) -> Result { + let krate = CrateNum::decode(d)?; let index = u32::decode(d)?; // Do this after decoding, so that we decode a `CrateNum` // if necessary - if index == ExpnId::root().as_u32() { + if index == 0 { debug!("decode_expn_id: deserialized root"); return Ok(ExpnId::root()); } + if krate != LOCAL_CRATE { + let expn_id = ExpnId { krate, local_id: ExpnIndex::from_u32(index) }; + if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { + return Ok(expn_id); + } + let (expn_data, hash) = decode_foreign(d, expn_id)?; + debug_assert_eq!(krate, expn_data.krate); + debug_assert_eq!(expn_data.orig_id, Some(index)); + let expn_id = HygieneData::with(|hygiene_data| { + debug_assert_eq!(expn_data.orig_id, Some(index)); + let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data); + debug_assert!(_old_data.is_none()); + let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); + debug_assert!(_old_hash.is_none()); + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); + expn_id + }); + return Ok(expn_id); + } + let outer_expns = &context.remapped_expns; // Ensure that the lock() temporary is dropped early { if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { - return Ok(expn_id); + return Ok(expn_id.to_expn_id()); } } // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds let (mut expn_data, hash) = decode_data(d, index)?; + debug_assert_eq!(krate, expn_data.krate); let expn_id = HygieneData::with(|hygiene_data| { - if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { - return expn_id; + if let Some(expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { + return *expn_id; } - let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); - // If we just deserialized an `ExpnData` owned by // the local crate, its `orig_id` will be stale, // so we need to update it to its own value. // This only happens when we deserialize the incremental cache, // since a crate will never decode its own metadata. - if expn_data.krate == LOCAL_CRATE { - expn_data.orig_id = Some(expn_id.0); - } - - hygiene_data.expn_data.push(Some(expn_data)); - hygiene_data.expn_hashes.push(hash); - let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); - debug_assert!(_old_id.is_none()); + let expn_id = hygiene_data.local_expn_data.next_index(); + expn_data.orig_id = Some(expn_id.as_u32()); + hygiene_data.local_expn_data.push(Some(expn_data)); + let _eid = hygiene_data.local_expn_hashes.push(hash); + debug_assert_eq!(expn_id, _eid); let mut expns = outer_expns.lock(); let new_len = index as usize + 1; @@ -1131,6 +1273,10 @@ pub fn decode_expn_id_incrcomp( } expns[index as usize] = Some(expn_id); drop(expns); + let expn_id = expn_id.to_expn_id(); + + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); expn_id }); Ok(expn_id) @@ -1138,39 +1284,42 @@ pub fn decode_expn_id_incrcomp( pub fn decode_expn_id( d: &mut D, - decode_data: impl FnOnce(CrateNum, u32) -> (ExpnData, ExpnHash), + decode_data: impl FnOnce(CrateNum, ExpnIndex) -> (ExpnData, ExpnHash), ) -> Result { - let index = u32::decode(d)?; let krate = CrateNum::decode(d)?; + let index = u32::decode(d)?; // Do this after decoding, so that we decode a `CrateNum` // if necessary - if index == ExpnId::root().as_u32() { + if index == 0 { debug!("decode_expn_id: deserialized root"); return Ok(ExpnId::root()); } + let index = ExpnIndex::from_u32(index); + // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE. debug_assert_ne!(krate, LOCAL_CRATE); + let expn_id = ExpnId { krate, local_id: index }; + + // Fast path if the expansion has already been decoded. + if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { + return Ok(expn_id); + } // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds let (expn_data, hash) = decode_data(krate, index); debug_assert_eq!(krate, expn_data.krate); - debug_assert_eq!(expn_data.orig_id, Some(index)); - - let expn_id = HygieneData::with(|hygiene_data| { - if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { - return expn_id; - } + debug_assert_eq!(Some(index.as_u32()), expn_data.orig_id); - let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); - hygiene_data.expn_data.push(Some(expn_data)); - hygiene_data.expn_hashes.push(hash); + HygieneData::with(|hygiene_data| { + let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data); + debug_assert!(_old_data.is_none()); + let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); + debug_assert!(_old_hash.is_none()); let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); debug_assert!(_old_id.is_none()); - - expn_id }); Ok(expn_id) @@ -1264,29 +1413,37 @@ fn for_all_ctxts_in Resul fn for_all_expns_in( expns: impl Iterator, - mut f: impl FnMut(u32, ExpnId, ExpnData, ExpnHash) -> Result<(), E>, + mut f: impl FnMut(ExpnId, ExpnData, ExpnHash) -> Result<(), E>, ) -> Result<(), E> { let all_data: Vec<_> = HygieneData::with(|data| { expns - .map(|expn| { - let idx = expn.0 as usize; - (expn, data.expn_data[idx].clone(), data.expn_hashes[idx].clone()) - }) + .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn).clone())) .collect() }); for (expn, data, hash) in all_data.into_iter() { - let data = data.unwrap_or_else(|| panic!("Missing data for {:?}", expn)); - f(expn.0, expn, data, hash)?; + f(expn, data, hash)?; } Ok(()) } +impl Encodable for LocalExpnId { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.to_expn_id().encode(e) + } +} + impl Encodable for ExpnId { default fn encode(&self, _: &mut E) -> Result<(), E::Error> { panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::()); } } +impl Decodable for LocalExpnId { + fn decode(d: &mut D) -> Result { + ExpnId::decode(d).map(ExpnId::expect_local) + } +} + impl Decodable for ExpnId { default fn decode(_: &mut D) -> Result { panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::()); @@ -1309,12 +1466,12 @@ pub fn raw_encode_expn_id_incrcomp( context: &HygieneEncodeContext, e: &mut E, ) -> Result<(), E::Error> { - // Record the fact that we need to serialize the corresponding - // `ExpnData` + // Record the fact that we need to serialize the corresponding `ExpnData` if !context.serialized_expns.lock().contains(&expn) { context.latest_expns.lock().insert(expn); } - expn.0.encode(e) + expn.krate.encode(e)?; + expn.local_id.as_u32().encode(e) } pub fn raw_encode_expn_id( @@ -1322,21 +1479,19 @@ pub fn raw_encode_expn_id( context: &HygieneEncodeContext, e: &mut E, ) -> Result<(), E::Error> { - let data = expn.expn_data(); // We only need to serialize the ExpnData // if it comes from this crate. // We currently don't serialize any hygiene information data for // proc-macro crates: see the `SpecializedEncoder` impl // for crate metadata. - if data.krate == LOCAL_CRATE { - // Record the fact that we need to serialize the corresponding - // `ExpnData` + // Record the fact that we need to serialize the corresponding `ExpnData` + if expn.krate == LOCAL_CRATE { if !context.serialized_expns.lock().contains(&expn) { context.latest_expns.lock().insert(expn); } } - data.orig_id.expect("Missing orig_id").encode(e)?; - data.krate.encode(e) + expn.krate.encode(e)?; + expn.local_id.as_u32().encode(e) } impl Encodable for SyntaxContext { @@ -1360,7 +1515,7 @@ impl Decodable for SyntaxContext { /// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized /// from another crate's metadata - since `ExpnData` includes a `krate` field, /// collisions are only possible between `ExpnId`s within the same crate. -fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) { +fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { let mut expn_data = expn_id.expn_data(); // This disambiguator should not have been set yet. assert_eq!( @@ -1399,10 +1554,10 @@ fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) { let expn_hash = ExpnHash(expn_hash); HygieneData::with(|data| { - data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = disambiguator; - debug_assert_eq!(data.expn_hashes[expn_id.0 as usize].0, Fingerprint::ZERO); - data.expn_hashes[expn_id.0 as usize] = expn_hash; - let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id); + data.local_expn_data[expn_id].as_mut().unwrap().disambiguator = disambiguator; + debug_assert_eq!(data.local_expn_hashes[expn_id].0, Fingerprint::ZERO); + data.local_expn_hashes[expn_id] = expn_hash; + let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id()); debug_assert!(_old_id.is_none()); }); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7a1ee20ee7951..1c95cc91208d3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -38,7 +38,7 @@ use edition::Edition; pub mod hygiene; use hygiene::Transparency; pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind}; -pub use hygiene::{ExpnData, ExpnHash, ExpnId, SyntaxContext}; +pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; pub mod def_id; use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE}; pub mod lev_distance; From 078dd37f882a59d4277d80b829d729bfd2b5a5c2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 25 Jun 2021 20:43:04 +0200 Subject: [PATCH 23/52] Use LocalExpnId where possible. --- compiler/rustc_ast/src/node_id.rs | 10 ++-- .../src/deriving/clone.rs | 5 +- .../src/deriving/generic/mod.rs | 2 +- .../src/proc_macro_harness.rs | 2 +- .../src/standard_library_imports.rs | 4 +- .../rustc_builtin_macros/src/test_harness.rs | 5 +- compiler/rustc_expand/src/base.rs | 40 +++++++++------- compiler/rustc_expand/src/expand.rs | 6 +-- compiler/rustc_expand/src/mbe/transcribe.rs | 6 +-- .../rustc_resolve/src/build_reduced_graph.rs | 37 +++++++++------ compiler/rustc_resolve/src/def_collector.rs | 10 ++-- compiler/rustc_resolve/src/imports.rs | 15 +++--- compiler/rustc_resolve/src/lib.rs | 46 ++++++++++--------- compiler/rustc_resolve/src/macros.rs | 35 ++++++++------ compiler/rustc_span/src/hygiene.rs | 15 +----- src/test/ui/hygiene/unpretty-debug.stdout | 8 ++-- .../ui/proc-macro/meta-macro-hygiene.stdout | 34 +++++++------- .../nonterminal-token-hygiene.stdout | 32 ++++++------- src/tools/rustfmt/src/utils.rs | 4 +- 19 files changed, 169 insertions(+), 147 deletions(-) diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index e1e7d757d7e62..7f928cb576180 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -1,4 +1,4 @@ -use rustc_span::{ExpnId, LocalExpnId}; +use rustc_span::LocalExpnId; use std::fmt; rustc_index::newtype_index! { @@ -24,12 +24,12 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0); pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; impl NodeId { - pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self { - NodeId::from_u32(expn_id.expect_local().as_u32()) + pub fn placeholder_from_expn_id(expn_id: LocalExpnId) -> Self { + NodeId::from_u32(expn_id.as_u32()) } - pub fn placeholder_to_expn_id(self) -> ExpnId { - LocalExpnId::from_u32(self.as_u32()).to_expn_id() + pub fn placeholder_to_expn_id(self) -> LocalExpnId { + LocalExpnId::from_u32(self.as_u32()) } } diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index ca1226b445d97..90cdd62144d72 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -36,8 +36,9 @@ pub fn expand_deriving_clone( Annotatable::Item(ref annitem) => match annitem.kind { ItemKind::Struct(_, Generics { ref params, .. }) | ItemKind::Enum(_, Generics { ref params, .. }) => { - let container_id = cx.current_expansion.id.expn_data().parent; - if cx.resolver.has_derive_copy(container_id) + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); + let has_derive_copy = cx.resolver.has_derive_copy(container_id); + if has_derive_copy && !params .iter() .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index a3decff3ae7e1..417dedab60d08 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -410,7 +410,7 @@ impl<'a> TraitDef<'a> { .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; - let container_id = cx.current_expansion.id.expn_data().parent; + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); let use_temporaries = is_packed && always_copy; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a8c61d53346de..f83329ecba824 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -304,7 +304,7 @@ fn mk_decls( &[sym::rustc_attrs, sym::proc_macro_internals], None, ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id); + let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); let proc_macro = Ident::new(sym::proc_macro, span); let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index fbd8be22a9de2..e0d57267525d9 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -34,8 +34,8 @@ pub fn inject( &[sym::prelude_import], None, ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id); - let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); + let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); + let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id()); let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); let cx = ExtCtxt::new(sess, ecfg, resolver, None); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index c8a7ff67b4d50..74a97a4058fac 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -126,7 +126,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { for test in &mut tests { // See the comment on `mk_main` for why we're using // `apply_mark` directly. - test.ident.span = test.ident.span.apply_mark(expn_id, Transparency::Opaque); + test.ident.span = + test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); } self.cx.test_cases.extend(tests); } @@ -223,7 +224,7 @@ fn generate_test_harness( &[sym::test, sym::rustc_attrs], None, ); - let def_site = DUMMY_SP.with_def_site_ctxt(expn_id); + let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); // Remove the entry points let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site }; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 0183add495777..497be2d931872 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -16,7 +16,7 @@ use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; +use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP}; @@ -813,7 +813,7 @@ impl SyntaxExtension { pub fn expn_data( &self, - parent: ExpnId, + parent: LocalExpnId, call_site: Span, descr: Symbol, macro_def_id: Option, @@ -821,7 +821,7 @@ impl SyntaxExtension { ) -> ExpnData { ExpnData::new( ExpnKind::Macro(self.macro_kind(), descr), - parent, + parent.to_expn_id(), call_site, self.span, self.allow_internal_unstable.clone(), @@ -843,7 +843,11 @@ pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; fn resolve_dollar_crates(&mut self); - fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment); + fn visit_ast_fragment_with_placeholders( + &mut self, + expn_id: LocalExpnId, + fragment: &AstFragment, + ); fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind); fn expansion_for_ast_pass( @@ -852,37 +856,41 @@ pub trait ResolverExpand { pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> ExpnId; + ) -> LocalExpnId; fn resolve_imports(&mut self); fn resolve_macro_invocation( &mut self, invoc: &Invocation, - eager_expansion_root: ExpnId, + eager_expansion_root: LocalExpnId, force: bool, ) -> Result, Indeterminate>; fn check_unused_macros(&mut self); /// Some parent node that is close enough to the given macro call. - fn lint_node_id(&self, expn_id: ExpnId) -> NodeId; + fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId; // Resolver interfaces for specific built-in macros. /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? - fn has_derive_copy(&self, expn_id: ExpnId) -> bool; + fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool; /// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`. fn resolve_derives( &mut self, - expn_id: ExpnId, + expn_id: LocalExpnId, force: bool, derive_paths: &dyn Fn() -> DeriveResolutions, ) -> Result<(), Indeterminate>; /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId` /// back from resolver. - fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option; + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option; /// Path resolution logic for `#[cfg_accessible(path)]`. - fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result; + fn cfg_accessible( + &mut self, + expn_id: LocalExpnId, + path: &ast::Path, + ) -> Result; /// Decodes the proc-macro quoted span in the specified crate, with the specified id. /// No caching is performed. @@ -913,7 +921,7 @@ impl ModuleData { #[derive(Clone)] pub struct ExpansionData { - pub id: ExpnId, + pub id: LocalExpnId, pub depth: usize, pub module: Rc, pub dir_ownership: DirOwnership, @@ -958,7 +966,7 @@ impl<'a> ExtCtxt<'a> { extern_mod_loaded, root_path: PathBuf::new(), current_expansion: ExpansionData { - id: ExpnId::root(), + id: LocalExpnId::ROOT, depth: 0, module: Default::default(), dir_ownership: DirOwnership::Owned { relative: None }, @@ -995,19 +1003,19 @@ impl<'a> ExtCtxt<'a> { /// Equivalent of `Span::def_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_def_site_ctxt(&self, span: Span) -> Span { - span.with_def_site_ctxt(self.current_expansion.id) + span.with_def_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Equivalent of `Span::call_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_call_site_ctxt(&self, span: Span) -> Span { - span.with_call_site_ctxt(self.current_expansion.id) + span.with_call_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_mixed_site_ctxt(&self, span: Span) -> Span { - span.with_mixed_site_ctxt(self.current_expansion.id) + span.with_mixed_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Returns span for the macro which originally caused the current expansion to happen. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1ab7e15019eff..b9d4096241142 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -31,7 +31,7 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Limit; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{ExpnId, FileName, Span}; +use rustc_span::{FileName, LocalExpnId, Span}; use smallvec::{smallvec, SmallVec}; use std::ops::DerefMut; @@ -508,7 +508,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .map(|(path, item, _exts)| { // FIXME: Consider using the derive resolutions (`_exts`) // instead of enqueuing the derives to be resolved again later. - let expn_id = ExpnId::fresh_empty(); + let expn_id = LocalExpnId::fresh_empty(); derive_invocations.push(( Invocation { kind: InvocationKind::Derive { path, item }, @@ -993,7 +993,7 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let expn_id = ExpnId::fresh_empty(); + let expn_id = LocalExpnId::fresh_empty(); let vis = kind.placeholder_visibility(); self.invocations.push(( Invocation { diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index f9e7c4254bc49..9ed5c8b8ffba5 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{pluralize, PResult}; -use rustc_span::hygiene::{ExpnId, Transparency}; +use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; @@ -16,7 +16,7 @@ use smallvec::{smallvec, SmallVec}; use std::mem; // A Marker adds the given mark to the syntax context. -struct Marker(ExpnId, Transparency); +struct Marker(LocalExpnId, Transparency); impl MutVisitor for Marker { fn token_visiting_enabled(&self) -> bool { @@ -24,7 +24,7 @@ impl MutVisitor for Marker { } fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0, self.1) + *span = span.apply_mark(self.0.to_expn_id(), self.1) } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 35e7688fbe45a..178d727418d74 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -31,7 +31,7 @@ use rustc_middle::bug; use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::CrateStore; use rustc_middle::ty; -use rustc_span::hygiene::{ExpnId, MacroKind}; +use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -42,7 +42,7 @@ use tracing::debug; type Res = def::Res; -impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, ExpnId) { +impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Module(self.0), @@ -54,7 +54,7 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, ExpnId) { } } -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, false), @@ -68,7 +68,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId) { struct IsMacroExport; -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId, IsMacroExport) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, true), @@ -157,7 +157,12 @@ impl<'a> Resolver<'a> { crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { let def_id = match expn_id.expn_data().macro_def_id { Some(def_id) => def_id, - None => return self.ast_transform_scopes.get(&expn_id).unwrap_or(&self.graph_root), + None => { + return expn_id + .as_local() + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) + .unwrap_or(&self.graph_root); + } }; self.macro_def_scope_from_def_id(def_id) } @@ -739,7 +744,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if ptr::eq(parent, self.r.graph_root) { if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { - if expansion != ExpnId::root() + if expansion != LocalExpnId::ROOT && orig_name.is_some() && entry.extern_crate_item.is_none() { @@ -769,7 +774,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { no_implicit_prelude: parent.no_implicit_prelude || { self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude) }, - ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) + ..ModuleData::new( + Some(parent), + module_kind, + def_id, + expansion.to_expn_id(), + item.span, + ) }); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.r.module_map.insert(local_def_id, module); @@ -808,7 +819,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, module_kind, parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), item.span, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -883,7 +894,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, module_kind, parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), item.span, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -926,7 +937,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, ModuleKind::Block(block.id), parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), block.span, ); self.r.block_map.insert(block.id, module); @@ -946,7 +957,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, ModuleKind::Def(kind, def_id, ident.name), def_id, - expansion, + expansion.to_expn_id(), span, ); self.r.define(parent, ident, TypeNS, (module, vis, span, expansion)); @@ -1112,7 +1123,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }) }; - let allow_shadowing = self.parent_scope.expansion == ExpnId::root(); + let allow_shadowing = self.parent_scope.expansion == LocalExpnId::ROOT; if let Some(span) = import_all { let import = macro_use_import(self, span); self.r.potentially_unused_imports.push(import); @@ -1175,7 +1186,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { false } - fn visit_invoc(&mut self, id: NodeId) -> ExpnId { + fn visit_invoc(&mut self, id: NodeId) -> LocalExpnId { let invoc_id = id.placeholder_to_expn_id(); let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 17f0c39e39735..6f4f1bdaea1b7 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -6,7 +6,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; -use rustc_span::hygiene::ExpnId; +use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use tracing::debug; @@ -14,7 +14,7 @@ use tracing::debug; crate fn collect_definitions( resolver: &mut Resolver<'_>, fragment: &AstFragment, - expansion: ExpnId, + expansion: LocalExpnId, ) { let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); @@ -25,14 +25,14 @@ struct DefCollector<'a, 'b> { resolver: &'a mut Resolver<'b>, parent_def: LocalDefId, impl_trait_context: ImplTraitContext, - expansion: ExpnId, + expansion: LocalExpnId, } impl<'a, 'b> DefCollector<'a, 'b> { fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.resolver.create_def(parent_def, node_id, data, self.expansion, span) + self.resolver.create_def(parent_def, node_id, data, self.expansion.to_expn_id(), span) } fn with_parent(&mut self, parent_def: LocalDefId, f: F) { @@ -285,7 +285,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { item_def, node_id, DefPathData::ImplTrait, - self.expansion, + self.expansion.to_expn_id(), ty.span, ), ImplTraitContext::Existential => { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 26858915f45a0..acfa389fed58a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -22,7 +22,7 @@ use rustc_middle::span_bug; use rustc_middle::ty; use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::hygiene::ExpnId; +use rustc_span::hygiene::LocalExpnId; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{MultiSpan, Span}; @@ -237,8 +237,9 @@ impl<'a> Resolver<'a> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - let binding = (module, ty::Visibility::Public, module.span, ExpnId::root()) - .to_name_binding(self.arenas); + let binding = + (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) + .to_name_binding(self.arenas); return Ok(binding); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. @@ -265,7 +266,7 @@ impl<'a> Resolver<'a> { self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. if let Some(binding) = resolution.binding { - if !restricted_shadowing && binding.expansion != ExpnId::root() { + if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { if let NameBindingKind::Res(_, true) = binding.kind { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } @@ -307,7 +308,7 @@ impl<'a> Resolver<'a> { if let Some(shadowed_glob) = resolution.shadowed_glob { // Forbid expanded shadowing to avoid time travel. if restricted_shadowing - && binding.expansion != ExpnId::root() + && binding.expansion != LocalExpnId::ROOT && binding.res() != shadowed_glob.res() { self.ambiguity_errors.push(AmbiguityError { @@ -521,7 +522,7 @@ impl<'a> Resolver<'a> { if old_glob { (old_binding, binding) } else { (binding, old_binding) }; if glob_binding.res() != nonglob_binding.res() && key.ns == MacroNS - && nonglob_binding.expansion != ExpnId::root() + && nonglob_binding.expansion != LocalExpnId::ROOT { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, @@ -1271,7 +1272,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { target: Ident, ) { // Skip if the import was produced by a macro. - if import.parent_scope.expansion != ExpnId::root() { + if import.parent_scope.expansion != LocalExpnId::ROOT { return; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fb2eb749e118f..7114fd33188d9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -53,7 +53,7 @@ use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency}; +use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::source_map::{CachingSourceMapView, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -103,7 +103,7 @@ impl Determinacy { /// but not for late resolution yet. #[derive(Clone, Copy)] enum Scope<'a> { - DeriveHelpers(ExpnId), + DeriveHelpers(LocalExpnId), DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, @@ -143,7 +143,7 @@ enum ScopeSet<'a> { #[derive(Clone, Copy, Debug)] pub struct ParentScope<'a> { module: Module<'a>, - expansion: ExpnId, + expansion: LocalExpnId, macro_rules: MacroRulesScopeRef<'a>, derives: &'a [ast::Path], } @@ -154,7 +154,7 @@ impl<'a> ParentScope<'a> { pub fn module(module: Module<'a>, resolver: &Resolver<'a>) -> ParentScope<'a> { ParentScope { module, - expansion: ExpnId::root(), + expansion: LocalExpnId::ROOT, macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], } @@ -515,7 +515,7 @@ pub struct ModuleData<'a> { populate_on_access: Cell, /// Macro invocations that can expand into items in this module. - unexpanded_invocations: RefCell>, + unexpanded_invocations: RefCell>, /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, @@ -645,7 +645,7 @@ impl<'a> fmt::Debug for ModuleData<'a> { pub struct NameBinding<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, - expansion: ExpnId, + expansion: LocalExpnId, span: Span, vis: ty::Visibility, } @@ -829,7 +829,11 @@ impl<'a> NameBinding<'a> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after(&self, invoc_parent_expansion: ExpnId, binding: &NameBinding<'_>) -> bool { + fn may_appear_after( + &self, + invoc_parent_expansion: LocalExpnId, + binding: &NameBinding<'_>, + ) -> bool { // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. @@ -966,7 +970,7 @@ pub struct Resolver<'a> { dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], local_macro_def_scopes: FxHashMap>, - ast_transform_scopes: FxHashMap>, + ast_transform_scopes: FxHashMap>, unused_macros: FxHashMap, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. @@ -978,18 +982,18 @@ pub struct Resolver<'a> { /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global /// context, so they attach the markers to derive container IDs using this resolver table. - containers_deriving_copy: FxHashSet, + containers_deriving_copy: FxHashSet, /// Parent scopes in which the macros were invoked. /// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere. - invocation_parent_scopes: FxHashMap>, + invocation_parent_scopes: FxHashMap>, /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. - output_macro_rules_scopes: FxHashMap>, + output_macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap>, + helper_attrs: FxHashMap>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. - derive_data: FxHashMap, + derive_data: FxHashMap, /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, @@ -1018,7 +1022,7 @@ pub struct Resolver<'a> { /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. - invocation_parents: FxHashMap, + invocation_parents: FxHashMap, next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. @@ -1268,7 +1272,7 @@ impl<'a> Resolver<'a> { node_id_to_def_id.insert(CRATE_NODE_ID, root); let mut invocation_parents = FxHashMap::default(); - invocation_parents.insert(ExpnId::root(), (root, ImplTraitContext::Existential)); + invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential)); let mut extern_prelude: FxHashMap> = session .opts @@ -1342,7 +1346,7 @@ impl<'a> Resolver<'a> { dummy_binding: arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(Res::Err, false), ambiguity: None, - expansion: ExpnId::root(), + expansion: LocalExpnId::ROOT, span: DUMMY_SP, vis: ty::Visibility::Public, }), @@ -1392,7 +1396,7 @@ impl<'a> Resolver<'a> { }; let root_parent_scope = ParentScope::module(graph_root, &resolver); - resolver.invocation_parent_scopes.insert(ExpnId::root(), root_parent_scope); + resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver } @@ -1810,7 +1814,8 @@ impl<'a> Resolver<'a> { } scope = match scope { - Scope::DeriveHelpers(expn_id) if expn_id != ExpnId::root() => { + Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, + Scope::DeriveHelpers(expn_id) => { // Derive helpers are not visible to code generated by bang or derive macros. let expn_data = expn_id.expn_data(); match expn_data.kind { @@ -1818,10 +1823,9 @@ impl<'a> Resolver<'a> { | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { Scope::DeriveHelpersCompat } - _ => Scope::DeriveHelpers(expn_data.parent), + _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), } } - Scope::DeriveHelpers(..) => Scope::DeriveHelpersCompat, Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { MacroRulesScope::Binding(binding) => { @@ -3248,7 +3252,7 @@ impl<'a> Resolver<'a> { }; let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); Some( - (crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root()) + (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) .to_name_binding(self.arenas), ) } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 8686704388fee..86f271fdeceb8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -30,7 +30,7 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind}; +use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -62,7 +62,7 @@ pub enum MacroRulesScope<'a> { Binding(&'a MacroRulesBinding<'a>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. - Invocation(ExpnId), + Invocation(LocalExpnId), } /// `macro_rules!` scopes are always kept by reference and inside a cell. @@ -190,7 +190,11 @@ impl<'a> ResolverExpand for Resolver<'a> { }); } - fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) { + fn visit_ast_fragment_with_placeholders( + &mut self, + expansion: LocalExpnId, + fragment: &AstFragment, + ) { // Integrate the new AST fragment into all the definition and module structures. // We are inside the `expansion` now, but other parent scope components are still the same. let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] }; @@ -216,9 +220,9 @@ impl<'a> ResolverExpand for Resolver<'a> { pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> ExpnId { + ) -> LocalExpnId { let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id)); - let expn_id = ExpnId::fresh( + let expn_id = LocalExpnId::fresh( ExpnData::allow_unstable( ExpnKind::AstPass(pass), call_site, @@ -244,7 +248,7 @@ impl<'a> ResolverExpand for Resolver<'a> { fn resolve_macro_invocation( &mut self, invoc: &Invocation, - eager_expansion_root: ExpnId, + eager_expansion_root: LocalExpnId, force: bool, ) -> Result, Indeterminate> { let invoc_id = invoc.expansion_data.id; @@ -328,7 +332,7 @@ impl<'a> ResolverExpand for Resolver<'a> { | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { break; } - _ => expn_id = expn_data.parent, + _ => expn_id = expn_data.parent.expect_local(), } } } @@ -344,7 +348,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } } - fn lint_node_id(&self, expn_id: ExpnId) -> NodeId { + fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId { // FIXME - make this more precise. This currently returns the NodeId of the // nearest closing item - we should try to return the closest parent of the ExpnId self.invocation_parents @@ -352,13 +356,13 @@ impl<'a> ResolverExpand for Resolver<'a> { .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]) } - fn has_derive_copy(&self, expn_id: ExpnId) -> bool { + fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool { self.containers_deriving_copy.contains(&expn_id) } fn resolve_derives( &mut self, - expn_id: ExpnId, + expn_id: LocalExpnId, force: bool, derive_paths: &dyn Fn() -> DeriveResolutions, ) -> Result<(), Indeterminate> { @@ -423,7 +427,7 @@ impl<'a> ResolverExpand for Resolver<'a> { Ok(()) } - fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option { + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option { self.derive_data.remove(&expn_id).map(|data| data.resolutions) } @@ -431,7 +435,11 @@ impl<'a> ResolverExpand for Resolver<'a> { // Returns true if the path can certainly be resolved in one of three namespaces, // returns false if the path certainly cannot be resolved in any of the three namespaces. // Returns `Indeterminate` if we cannot give a certain answer yet. - fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result { + fn cfg_accessible( + &mut self, + expn_id: LocalExpnId, + path: &ast::Path, + ) -> Result { let span = path.span; let path = &Segment::from_path(path); let parent_scope = self.invocation_parent_scopes[&expn_id]; @@ -714,7 +722,8 @@ impl<'a> Resolver<'a> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ok = |res, span, arenas| { Ok(( - (res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas), + (res, ty::Visibility::Public, span, LocalExpnId::ROOT) + .to_name_binding(arenas), Flags::empty(), )) }; diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 14b6811298261..138ec061423bd 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -198,19 +198,6 @@ impl ExpnId { ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) } } - pub fn fresh_empty() -> ExpnId { - LocalExpnId::fresh_empty().to_expn_id() - } - - pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> ExpnId { - LocalExpnId::fresh(expn_data, ctx).to_expn_id() - } - - #[inline] - pub fn set_expn_data(self, expn_data: ExpnData, ctx: impl HashStableContext) { - self.expect_local().set_expn_data(expn_data, ctx) - } - #[inline] pub fn expn_hash(self) -> ExpnHash { HygieneData::with(|data| data.expn_hash(self)) @@ -819,7 +806,7 @@ impl Span { transparency: Transparency, ctx: impl HashStableContext, ) -> Span { - let expn_id = ExpnId::fresh(expn_data, ctx); + let expn_id = LocalExpnId::fresh(expn_data, ctx).to_expn_id(); HygieneData::with(|data| { self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout index 84ca046212dc5..ffb9f9eed41fb 100644 --- a/src/test/ui/hygiene/unpretty-debug.stdout +++ b/src/test/ui/hygiene/unpretty-debug.stdout @@ -19,10 +19,10 @@ fn y /* 0#0 */() { } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent) */ diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index dc63d014451db..2524d8273b705 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -43,23 +43,23 @@ fn main /* 0#0 */() { ; } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") -3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") -5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") +crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), Opaque) -#2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(3), Opaque) -#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#5: parent: #0, outer_mark: (ExpnId(4), Opaque) -#6: parent: #4, outer_mark: (ExpnId(4), Transparent) -#7: parent: #0, outer_mark: (ExpnId(4), SemiTransparent) -#8: parent: #0, outer_mark: (ExpnId(5), Opaque) -#9: parent: #5, outer_mark: (ExpnId(5), Transparent) -#10: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) +#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) +#3: parent: #0, outer_mark: (crate2::{{expn1}}, Opaque) +#4: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#6: parent: #4, outer_mark: (crate0::{{expn3}}, Transparent) +#7: parent: #0, outer_mark: (crate0::{{expn3}}, SemiTransparent) +#8: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) +#9: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) +#10: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout index 75e6a49b314df..b5ab82737e9b6 100644 --- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -67,22 +67,22 @@ fn main /* 0#0 */() { } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") -3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") -5: parent: ExpnId(4), call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") +crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), Opaque) -#2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(3), Opaque) -#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#5: parent: #0, outer_mark: (ExpnId(4), Opaque) -#6: parent: #4, outer_mark: (ExpnId(4), Opaque) -#7: parent: #0, outer_mark: (ExpnId(5), Opaque) -#8: parent: #6, outer_mark: (ExpnId(5), Transparent) -#9: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) +#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) +#3: parent: #0, outer_mark: (crate2::{{expn1}}, Opaque) +#4: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#6: parent: #4, outer_mark: (crate0::{{expn3}}, Opaque) +#7: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) +#8: parent: #6, outer_mark: (crate0::{{expn4}}, Transparent) +#9: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index d3c349fb701e1..614cda5f911c2 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{ }; use rustc_ast::ptr; use rustc_ast_pretty::pprust; -use rustc_span::{sym, symbol, BytePos, ExpnId, Span, Symbol, SyntaxContext}; +use rustc_span::{sym, symbol, BytePos, LocalExpnId, Span, Symbol, SyntaxContext}; use unicode_width::UnicodeWidthStr; use crate::comment::{filter_normal_code, CharClasses, FullCodeCharKind, LineClasses}; @@ -675,7 +675,7 @@ pub(crate) trait NodeIdExt { impl NodeIdExt for NodeId { fn root() -> NodeId { - NodeId::placeholder_from_expn_id(ExpnId::root()) + NodeId::placeholder_from_expn_id(LocalExpnId::ROOT) } } From 2fe37c5bd1cc7d6cfa176f408c2b834e1b2617bf Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 10:38:06 +0200 Subject: [PATCH 24/52] Choose encoding format in caller code. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 9 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 10 +- .../src/ty/query/on_disk_cache.rs | 23 +++-- compiler/rustc_span/src/hygiene.rs | 98 +++++-------------- 4 files changed, 55 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4b72ac8695794..8b8ca987b380d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -377,7 +377,11 @@ impl<'a, 'tcx> Decodable> for ExpnId { let local_cdata = decoder.cdata(); let sess = decoder.sess.unwrap(); - rustc_span::hygiene::decode_expn_id(decoder, |cnum, index| { + let cnum = CrateNum::decode(decoder)?; + let index = u32::decode(decoder)?; + + let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| { + let ExpnId { krate: cnum, local_id: index } = expn_id; // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s // are stored in the owning crate, to avoid duplication. debug_assert_ne!(cnum, LOCAL_CRATE); @@ -399,7 +403,8 @@ impl<'a, 'tcx> Decodable> for ExpnId { .unwrap() .decode((&crate_data, sess)); (expn_data, expn_hash) - }) + }); + Ok(expn_id) } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4684daef4a18c..6877d6ef542c7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -182,7 +182,15 @@ impl<'a, 'tcx> Encodable> for SyntaxContext { impl<'a, 'tcx> Encodable> for ExpnId { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - rustc_span::hygiene::raw_encode_expn_id(*self, &s.hygiene_ctxt, s) + if self.krate == LOCAL_CRATE { + // We will only write details for local expansions. Non-local expansions will fetch + // data from the corresponding crate's metadata. + // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external + // metadata from proc-macro crates. + s.hygiene_ctxt.schedule_expn_data_for_encoding(*self); + } + self.krate.encode(s)?; + self.local_id.encode(s) } } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 358d016368ee0..685cb3a61ecab 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -794,25 +794,26 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { + let krate = CrateNum::decode(decoder)?; + let index = u32::decode(decoder)?; + let expn_data = decoder.expn_data; + let tcx = decoder.tcx; rustc_span::hygiene::decode_expn_id_incrcomp( - decoder, + krate, + index, decoder.hygiene_context, - |this, index| { + |index| -> Result<(ExpnData, ExpnHash), _> { // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. // We look up the position of the associated `ExpnData` and decode it. let pos = expn_data .get(&index) .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data)); - this.with_position(pos.to_usize(), |decoder| { - let data: (ExpnData, ExpnHash) = decode_tagged(decoder, TAG_EXPN_DATA)?; - Ok(data) - }) - }, - |this, expn_id| { - Ok(this.tcx.untracked_resolutions.cstore.decode_expn_data(this.tcx.sess, expn_id)) + decoder + .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)) }, + |expn_id| tcx.untracked_resolutions.cstore.decode_expn_data(tcx.sess, expn_id), ) } } @@ -988,7 +989,9 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - rustc_span::hygiene::raw_encode_expn_id_incrcomp(*self, s.hygiene_context, s) + s.hygiene_context.schedule_expn_data_for_encoding(*self); + self.krate.encode(s)?; + self.local_id.as_u32().encode(s) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 138ec061423bd..198bb5881422f 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -261,6 +261,8 @@ pub struct HygieneData { /// first and then resolved later), so we use an `Option` here. local_expn_data: IndexVec>, local_expn_hashes: IndexVec, + /// Data and hash information from external crates. We may eventually want to remove these + /// maps, and fetch the information directly from the other crate's metadata like DefIds do. foreign_expn_data: FxHashMap, foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, @@ -1130,6 +1132,13 @@ pub struct HygieneEncodeContext { } impl HygieneEncodeContext { + /// Record the fact that we need to serialize the corresponding `ExpnData`. + pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) { + if !self.serialized_expns.lock().contains(&expn) { + self.latest_expns.lock().insert(expn); + } + } + pub fn encode( &self, encoder: &mut T, @@ -1186,15 +1195,13 @@ pub struct HygieneDecodeContext { remapped_expns: Lock>>, } -pub fn decode_expn_id_incrcomp( - d: &mut D, +pub fn decode_expn_id_incrcomp( + krate: CrateNum, + index: u32, context: &HygieneDecodeContext, - decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, - decode_foreign: impl FnOnce(&mut D, ExpnId) -> Result<(ExpnData, ExpnHash), D::Error>, -) -> Result { - let krate = CrateNum::decode(d)?; - let index = u32::decode(d)?; - + decode_data: impl FnOnce(u32) -> Result<(ExpnData, ExpnHash), E>, + decode_foreign: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash), +) -> Result { // Do this after decoding, so that we decode a `CrateNum` // if necessary if index == 0 { @@ -1203,23 +1210,7 @@ pub fn decode_expn_id_incrcomp( } if krate != LOCAL_CRATE { - let expn_id = ExpnId { krate, local_id: ExpnIndex::from_u32(index) }; - if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { - return Ok(expn_id); - } - let (expn_data, hash) = decode_foreign(d, expn_id)?; - debug_assert_eq!(krate, expn_data.krate); - debug_assert_eq!(expn_data.orig_id, Some(index)); - let expn_id = HygieneData::with(|hygiene_data| { - debug_assert_eq!(expn_data.orig_id, Some(index)); - let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data); - debug_assert!(_old_data.is_none()); - let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); - debug_assert!(_old_hash.is_none()); - let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); - debug_assert!(_old_id.is_none()); - expn_id - }); + let expn_id = decode_expn_id(krate, index, decode_foreign); return Ok(expn_id); } @@ -1234,7 +1225,7 @@ pub fn decode_expn_id_incrcomp( // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds - let (mut expn_data, hash) = decode_data(d, index)?; + let (mut expn_data, hash) = decode_data(index)?; debug_assert_eq!(krate, expn_data.krate); let expn_id = HygieneData::with(|hygiene_data| { @@ -1269,18 +1260,14 @@ pub fn decode_expn_id_incrcomp( Ok(expn_id) } -pub fn decode_expn_id( - d: &mut D, - decode_data: impl FnOnce(CrateNum, ExpnIndex) -> (ExpnData, ExpnHash), -) -> Result { - let krate = CrateNum::decode(d)?; - let index = u32::decode(d)?; - - // Do this after decoding, so that we decode a `CrateNum` - // if necessary +pub fn decode_expn_id( + krate: CrateNum, + index: u32, + decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash), +) -> ExpnId { if index == 0 { debug!("decode_expn_id: deserialized root"); - return Ok(ExpnId::root()); + return ExpnId::root(); } let index = ExpnIndex::from_u32(index); @@ -1291,12 +1278,12 @@ pub fn decode_expn_id( // Fast path if the expansion has already been decoded. if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { - return Ok(expn_id); + return expn_id; } // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds - let (expn_data, hash) = decode_data(krate, index); + let (expn_data, hash) = decode_data(expn_id); debug_assert_eq!(krate, expn_data.krate); debug_assert_eq!(Some(index.as_u32()), expn_data.orig_id); @@ -1309,7 +1296,7 @@ pub fn decode_expn_id( debug_assert!(_old_id.is_none()); }); - Ok(expn_id) + expn_id } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` @@ -1448,39 +1435,6 @@ pub fn raw_encode_syntax_context( ctxt.0.encode(e) } -pub fn raw_encode_expn_id_incrcomp( - expn: ExpnId, - context: &HygieneEncodeContext, - e: &mut E, -) -> Result<(), E::Error> { - // Record the fact that we need to serialize the corresponding `ExpnData` - if !context.serialized_expns.lock().contains(&expn) { - context.latest_expns.lock().insert(expn); - } - expn.krate.encode(e)?; - expn.local_id.as_u32().encode(e) -} - -pub fn raw_encode_expn_id( - expn: ExpnId, - context: &HygieneEncodeContext, - e: &mut E, -) -> Result<(), E::Error> { - // We only need to serialize the ExpnData - // if it comes from this crate. - // We currently don't serialize any hygiene information data for - // proc-macro crates: see the `SpecializedEncoder` impl - // for crate metadata. - // Record the fact that we need to serialize the corresponding `ExpnData` - if expn.krate == LOCAL_CRATE { - if !context.serialized_expns.lock().contains(&expn) { - context.latest_expns.lock().insert(expn); - } - } - expn.krate.encode(e)?; - expn.local_id.as_u32().encode(e) -} - impl Encodable for SyntaxContext { default fn encode(&self, _: &mut E) -> Result<(), E::Error> { panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::()); From 37a13def486e2133db264ec9b83735c4c4546e58 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 15:51:25 +0200 Subject: [PATCH 25/52] Encode ExpnId using ExpnHash for incr. comp. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 38 ++++++ .../src/rmeta/decoder/cstore_impl.rs | 23 +--- compiler/rustc_middle/src/middle/cstore.rs | 5 +- .../src/ty/query/on_disk_cache.rs | 93 +++++++++----- compiler/rustc_span/src/def_id.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 121 ++++++++---------- 6 files changed, 161 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8b8ca987b380d..388a8bd22fb32 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -79,6 +79,8 @@ crate struct CrateMetadata { /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how /// this is used. def_path_hash_map: OnceCell>, + /// Likewise for ExpnHash. + expn_hash_map: OnceCell>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_state: AllocDecodingState, /// Caches decoded `DefKey`s. @@ -1619,6 +1621,41 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } + fn expn_hash_to_expn_id(&self, index_guess: u32, hash: ExpnHash) -> ExpnId { + debug_assert_eq!(ExpnId::from_hash(hash), None); + let index_guess = ExpnIndex::from_u32(index_guess); + let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); + + let index = if old_hash == Some(hash) { + // Fast path: the expn and its index is unchanged from the + // previous compilation session. There is no need to decode anything + // else. + index_guess + } else { + // Slow path: We need to find out the new `DefIndex` of the provided + // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` + // stored in this crate. + let map = self.cdata.expn_hash_map.get_or_init(|| { + let end_id = self.root.expn_hashes.size() as u32; + let mut map = + UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default()); + for i in 0..end_id { + let i = ExpnIndex::from_u32(i); + if let Some(hash) = self.root.expn_hashes.get(self, i) { + map.insert(hash.decode(self), i); + } else { + panic!("Missing expn_hash entry for {:?}", i); + } + } + map + }); + map[&hash] + }; + + let data = self.root.expn_data.get(self, index).unwrap().decode(self); + rustc_span::hygiene::register_expn_id(data, hash) + } + /// Imports the source_map from an external crate into the source_map of the crate /// currently being compiled (the "local crate"). /// @@ -1857,6 +1894,7 @@ impl CrateMetadata { raw_proc_macros, source_map_import_info: OnceCell::new(), def_path_hash_map: Default::default(), + expn_hash_map: Default::default(), alloc_decoding_state, cnum, cnum_map, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 67023e9e84e22..41839c58021ab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; -use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId}; +use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; @@ -494,23 +494,6 @@ impl CrateStore for CStore { fn as_any(&self) -> &dyn Any { self } - fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash) { - let crate_data = self.get_crate_data(expn_id.krate); - ( - crate_data - .root - .expn_data - .get(&crate_data, expn_id.local_id) - .unwrap() - .decode((&crate_data, sess)), - crate_data - .root - .expn_hashes - .get(&crate_data, expn_id.local_id) - .unwrap() - .decode((&crate_data, sess)), - ) - } fn crate_name(&self, cnum: CrateNum) -> Symbol { self.get_crate_data(cnum).root.name @@ -545,6 +528,10 @@ impl CrateStore for CStore { self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash) } + fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId { + self.get_crate_data(cnum).expn_hash_to_expn_id(index_guess, hash) + } + fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata { encoder::encode_metadata(tcx) } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index c10fcc2e90c7e..4c35b49bcefd7 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -11,8 +11,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; -use rustc_session::Session; -use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId}; +use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::Target; @@ -188,7 +187,6 @@ pub type MetadataLoaderDyn = dyn MetadataLoader + Sync; /// during resolve) pub trait CrateStore: std::fmt::Debug { fn as_any(&self) -> &dyn Any; - fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash); // Foreign definitions. // This information is safe to access, since it's hashed as part of the DefPathHash, which incr. @@ -209,6 +207,7 @@ pub trait CrateStore: std::fmt::Debug { index_guess: u32, hash: DefPathHash, ) -> Option; + fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId; // utility functions fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 685cb3a61ecab..03e3ca5ec6b8b 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -83,7 +83,7 @@ pub struct OnDiskCache<'sess> { // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively, // we could look up the `ExpnData` from the metadata of foreign crates, // but it seemed easier to have `OnDiskCache` be independent of the `CStore`. - expn_data: FxHashMap, + expn_data: UnhashMap, // Additional information used when decoding hygiene data. hygiene_context: HygieneDecodeContext, // Maps `DefPathHash`es to their `RawDefId`s from the *previous* @@ -91,6 +91,8 @@ pub struct OnDiskCache<'sess> { // we try to map a `DefPathHash` to its `DefId` in the current compilation // session. foreign_def_path_hashes: UnhashMap, + // Likewise for ExpnId. + foreign_expn_data: UnhashMap, // The *next* compilation sessison's `foreign_def_path_hashes` - at // the end of our current compilation session, this will get written @@ -118,8 +120,9 @@ struct Footer { // See `OnDiskCache.syntax_contexts` syntax_contexts: FxHashMap, // See `OnDiskCache.expn_data` - expn_data: FxHashMap, + expn_data: UnhashMap, foreign_def_path_hashes: UnhashMap, + foreign_expn_data: UnhashMap, } pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -217,6 +220,7 @@ impl<'sess> OnDiskCache<'sess> { alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), syntax_contexts: footer.syntax_contexts, expn_data: footer.expn_data, + foreign_expn_data: footer.foreign_expn_data, hygiene_context: Default::default(), foreign_def_path_hashes: footer.foreign_def_path_hashes, latest_foreign_def_path_hashes: Default::default(), @@ -236,7 +240,8 @@ impl<'sess> OnDiskCache<'sess> { prev_diagnostics_index: Default::default(), alloc_decoding_state: AllocDecodingState::new(Vec::new()), syntax_contexts: FxHashMap::default(), - expn_data: FxHashMap::default(), + expn_data: UnhashMap::default(), + foreign_expn_data: UnhashMap::default(), hygiene_context: Default::default(), foreign_def_path_hashes: Default::default(), latest_foreign_def_path_hashes: Default::default(), @@ -350,7 +355,8 @@ impl<'sess> OnDiskCache<'sess> { }; let mut syntax_contexts = FxHashMap::default(); - let mut expn_ids = FxHashMap::default(); + let mut expn_data = UnhashMap::default(); + let mut foreign_expn_data = UnhashMap::default(); // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current // session. @@ -363,13 +369,14 @@ impl<'sess> OnDiskCache<'sess> { syntax_contexts.insert(index, pos); Ok(()) }, - |encoder, index, expn_data, hash| -> FileEncodeResult { - if index.krate == LOCAL_CRATE { + |encoder, expn_id, data, hash| -> FileEncodeResult { + if expn_id.krate == LOCAL_CRATE { let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?; - expn_ids.insert(index.local_id.as_u32(), pos); + encoder.encode_tagged(TAG_EXPN_DATA, &data)?; + expn_data.insert(hash, pos); + } else { + foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); } - // TODO Handle foreign expansions. Ok(()) }, )?; @@ -387,7 +394,8 @@ impl<'sess> OnDiskCache<'sess> { diagnostics_index, interpret_alloc_index, syntax_contexts, - expn_data: expn_ids, + expn_data, + foreign_expn_data, foreign_def_path_hashes, }, )?; @@ -549,6 +557,7 @@ impl<'sess> OnDiskCache<'sess> { alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), syntax_contexts: &self.syntax_contexts, expn_data: &self.expn_data, + foreign_expn_data: &self.foreign_expn_data, hygiene_context: &self.hygiene_context, }; f(&mut decoder) @@ -643,7 +652,8 @@ pub struct CacheDecoder<'a, 'tcx> { file_index_to_stable_id: &'a FxHashMap, alloc_decoding_session: AllocDecodingSession<'a>, syntax_contexts: &'a FxHashMap, - expn_data: &'a FxHashMap, + expn_data: &'a UnhashMap, + foreign_expn_data: &'a UnhashMap, hygiene_context: &'a HygieneDecodeContext, } @@ -794,27 +804,43 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { - let krate = CrateNum::decode(decoder)?; - let index = u32::decode(decoder)?; - - let expn_data = decoder.expn_data; - let tcx = decoder.tcx; - rustc_span::hygiene::decode_expn_id_incrcomp( - krate, - index, - decoder.hygiene_context, - |index| -> Result<(ExpnData, ExpnHash), _> { - // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. - // We look up the position of the associated `ExpnData` and decode it. - let pos = expn_data - .get(&index) - .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data)); - - decoder - .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)) - }, - |expn_id| tcx.untracked_resolutions.cstore.decode_expn_data(tcx.sess, expn_id), - ) + let hash = ExpnHash::decode(decoder)?; + if hash.is_root() { + return Ok(ExpnId::root()); + } + + if let Some(expn_id) = ExpnId::from_hash(hash) { + return Ok(expn_id); + } + + let krate = decoder.cnum_map[&hash.stable_crate_id()]; + + let expn_id = if krate == LOCAL_CRATE { + // We look up the position of the associated `ExpnData` and decode it. + let pos = decoder + .expn_data + .get(&hash) + .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); + + let data: ExpnData = decoder + .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?; + rustc_span::hygiene::register_local_expn_id(data, hash) + } else { + let index_guess = decoder.foreign_expn_data[&hash]; + decoder.tcx.untracked_resolutions.cstore.expn_hash_to_expn_id(krate, index_guess, hash) + }; + + #[cfg(debug_assertions)] + { + use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + let mut hcx = decoder.tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); + let local_hash: u64 = hasher.finish(); + debug_assert_eq!(hash.local_hash(), local_hash); + } + + Ok(expn_id) } } @@ -990,8 +1016,7 @@ where { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { s.hygiene_context.schedule_expn_data_for_encoding(*self); - self.krate.encode(s)?; - self.local_id.as_u32().encode(s) + self.expn_hash().encode(s) } } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index c5d605ab57801..64baf94cc0063 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -136,7 +136,7 @@ impl Borrow for DefPathHash { /// further trouble. #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub struct StableCrateId(u64); +pub struct StableCrateId(pub(crate) u64); impl StableCrateId { pub fn to_u64(self) -> u64 { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 198bb5881422f..a6d77852c06a9 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -29,7 +29,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::with_session_globals; use crate::{HashStableContext, Span, DUMMY_SP}; -use crate::def_id::{CrateNum, DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -92,6 +92,34 @@ rustc_index::newtype_index! { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] pub struct ExpnHash(Fingerprint); +impl ExpnHash { + /// Returns the [StableCrateId] identifying the crate this [ExpnHash] + /// originates from. + #[inline] + pub fn stable_crate_id(self) -> StableCrateId { + StableCrateId(self.0.as_value().0) + } + + /// Returns the crate-local part of the [ExpnHash]. + /// + /// Used for tests. + #[inline] + pub fn local_hash(self) -> u64 { + self.0.as_value().1 + } + + #[inline] + pub fn is_root(self) -> bool { + self.0 == Fingerprint::ZERO + } + + /// Builds a new [ExpnHash] with the given [StableCrateId] and + /// `local_hash`, where `local_hash` must be unique within its crate. + fn new(stable_crate_id: StableCrateId, local_hash: u64) -> ExpnHash { + ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash)) + } +} + /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)] @@ -268,12 +296,12 @@ pub struct HygieneData { expn_hash_to_expn_id: UnhashMap, syntax_context_data: Vec, syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, - /// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value. + /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value. /// This is used by `update_disambiguator` to keep track of which `ExpnData`s /// would have collisions without a disambiguator. /// The keys of this map are always computed with `ExpnData.disambiguator` /// set to 0. - expn_data_disambiguators: FxHashMap, + expn_data_disambiguators: FxHashMap, } impl HygieneData { @@ -981,7 +1009,7 @@ impl ExpnData { } #[inline] - fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Fingerprint { + fn hash_expn(&self, ctx: &mut impl HashStableContext) -> u64 { let mut hasher = StableHasher::new(); self.hash_stable(ctx, &mut hasher); hasher.finish() @@ -1191,75 +1219,46 @@ pub struct HygieneDecodeContext { // so that multiple occurrences of the same serialized id are decoded to the same // `SyntaxContext` remapped_ctxts: Lock>>, - // The same as `remapepd_ctxts`, but for `ExpnId`s - remapped_expns: Lock>>, } -pub fn decode_expn_id_incrcomp( - krate: CrateNum, - index: u32, - context: &HygieneDecodeContext, - decode_data: impl FnOnce(u32) -> Result<(ExpnData, ExpnHash), E>, - decode_foreign: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash), -) -> Result { - // Do this after decoding, so that we decode a `CrateNum` - // if necessary - if index == 0 { - debug!("decode_expn_id: deserialized root"); - return Ok(ExpnId::root()); - } - - if krate != LOCAL_CRATE { - let expn_id = decode_expn_id(krate, index, decode_foreign); - return Ok(expn_id); - } - - let outer_expns = &context.remapped_expns; - - // Ensure that the lock() temporary is dropped early - { - if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { - return Ok(expn_id.to_expn_id()); - } - } - - // Don't decode the data inside `HygieneData::with`, since we need to recursively decode - // other ExpnIds - let (mut expn_data, hash) = decode_data(index)?; - debug_assert_eq!(krate, expn_data.krate); - - let expn_id = HygieneData::with(|hygiene_data| { - if let Some(expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { - return *expn_id; - } - +/// Register an expansion which has been decoded from the on-disk-cache for the local crate. +pub fn register_local_expn_id(mut data: ExpnData, hash: ExpnHash) -> ExpnId { + HygieneData::with(|hygiene_data| { // If we just deserialized an `ExpnData` owned by // the local crate, its `orig_id` will be stale, // so we need to update it to its own value. // This only happens when we deserialize the incremental cache, // since a crate will never decode its own metadata. let expn_id = hygiene_data.local_expn_data.next_index(); - expn_data.orig_id = Some(expn_id.as_u32()); - hygiene_data.local_expn_data.push(Some(expn_data)); + data.orig_id = Some(expn_id.as_u32()); + hygiene_data.local_expn_data.push(Some(data)); let _eid = hygiene_data.local_expn_hashes.push(hash); debug_assert_eq!(expn_id, _eid); - let mut expns = outer_expns.lock(); - let new_len = index as usize + 1; - if expns.len() < new_len { - expns.resize(new_len, None); - } - expns[index as usize] = Some(expn_id); - drop(expns); let expn_id = expn_id.to_expn_id(); let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); debug_assert!(_old_id.is_none()); expn_id + }) +} + +/// Register an expansion which has been decoded from the metadata of a foreign crate. +pub fn register_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { + let expn_id = + ExpnId { krate: data.krate, local_id: ExpnIndex::from_u32(data.orig_id.unwrap()) }; + HygieneData::with(|hygiene_data| { + let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data); + debug_assert!(_old_data.is_none()); + let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); + debug_assert!(_old_hash.is_none()); + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); }); - Ok(expn_id) + expn_id } +/// Decode an expansion from the metadata of a foreign crate. pub fn decode_expn_id( krate: CrateNum, index: u32, @@ -1287,16 +1286,7 @@ pub fn decode_expn_id( debug_assert_eq!(krate, expn_data.krate); debug_assert_eq!(Some(index.as_u32()), expn_data.orig_id); - HygieneData::with(|hygiene_data| { - let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data); - debug_assert!(_old_data.is_none()); - let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); - debug_assert!(_old_hash.is_none()); - let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); - debug_assert!(_old_id.is_none()); - }); - - expn_id + register_expn_id(expn_data, hash) } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` @@ -1493,7 +1483,8 @@ fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { }); } - let expn_hash = ExpnHash(expn_hash); + let expn_hash = + ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash); HygieneData::with(|data| { data.local_expn_data[expn_id].as_mut().unwrap().disambiguator = disambiguator; debug_assert_eq!(data.local_expn_hashes[expn_id].0, Fingerprint::ZERO); From dbd2d77641e87ac841d12db1ca8e1f38d96f85d3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 19:14:29 +0200 Subject: [PATCH 26/52] Drop orig_id. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 42 +++++--------------- 2 files changed, 10 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 388a8bd22fb32..a3f8c7e771b85 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1653,7 +1653,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; let data = self.root.expn_data.get(self, index).unwrap().decode(self); - rustc_span::hygiene::register_expn_id(data, hash) + rustc_span::hygiene::register_expn_id(index, data, hash) } /// Imports the source_map from an external crate into the source_map of the crate diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index a6d77852c06a9..32149f1550e30 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -179,14 +179,12 @@ impl LocalExpnId { } #[inline] - pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { + pub fn set_expn_data(self, expn_data: ExpnData, ctx: impl HashStableContext) { debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); HygieneData::with(|data| { let old_expn_data = &mut data.local_expn_data[self]; assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); - assert_eq!(expn_data.orig_id, None); debug_assert_eq!(expn_data.krate, LOCAL_CRATE); - expn_data.orig_id = Some(self.as_u32()); *old_expn_data = Some(expn_data); }); update_disambiguator(self, ctx) @@ -306,14 +304,13 @@ pub struct HygieneData { impl HygieneData { crate fn new(edition: Edition) -> Self { - let mut root_data = ExpnData::default( + let root_data = ExpnData::default( ExpnKind::Root, DUMMY_SP, edition, Some(CRATE_DEF_ID.to_def_id()), None, ); - root_data.orig_id = Some(0); HygieneData { local_expn_data: IndexVec::from_elem_n(Some(root_data), 1), @@ -339,13 +336,11 @@ impl HygieneData { with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) } - fn fresh_expn(&mut self, mut expn_data: Option) -> LocalExpnId { - let expn_id = self.local_expn_data.next_index(); - if let Some(data) = expn_data.as_mut() { + fn fresh_expn(&mut self, expn_data: Option) -> LocalExpnId { + if let Some(data) = &expn_data { debug_assert_eq!(data.krate, LOCAL_CRATE); - assert_eq!(data.orig_id, None); - data.orig_id = Some(expn_id.as_u32()); } + let expn_id = self.local_expn_data.next_index(); self.local_expn_data.push(expn_data); let _eid = self.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); debug_assert_eq!(expn_id, _eid); @@ -884,14 +879,6 @@ pub struct ExpnData { /// foreign `ExpnId`s will have their `ExpnData` looked up /// from the crate specified by `Crate krate: CrateNum, - /// The raw that this `ExpnData` had in its original crate. - /// An `ExpnData` can be created before being assigned an `ExpnId`, - /// so this might be `None` until `set_expn_data` is called - // This is used only for serialization/deserialization purposes: - // two `ExpnData`s that differ only in their `orig_id` should - // be considered equivalent. - #[stable_hasher(ignore)] - orig_id: Option, /// Used to force two `ExpnData`s to have different `Fingerprint`s. /// Due to macro expansion, it's possible to end up with two `ExpnId`s /// that have identical `ExpnData`s. This violates the contract of `HashStable` @@ -930,7 +917,6 @@ pub struct ExpnData { pub parent_module: Option, } -// These would require special handling of `orig_id`. impl !PartialEq for ExpnData {} impl !Hash for ExpnData {} @@ -959,7 +945,6 @@ impl ExpnData { macro_def_id, parent_module, krate: LOCAL_CRATE, - orig_id: None, disambiguator: 0, } } @@ -984,7 +969,6 @@ impl ExpnData { macro_def_id, parent_module, krate: LOCAL_CRATE, - orig_id: None, disambiguator: 0, } } @@ -1222,15 +1206,9 @@ pub struct HygieneDecodeContext { } /// Register an expansion which has been decoded from the on-disk-cache for the local crate. -pub fn register_local_expn_id(mut data: ExpnData, hash: ExpnHash) -> ExpnId { +pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { HygieneData::with(|hygiene_data| { - // If we just deserialized an `ExpnData` owned by - // the local crate, its `orig_id` will be stale, - // so we need to update it to its own value. - // This only happens when we deserialize the incremental cache, - // since a crate will never decode its own metadata. let expn_id = hygiene_data.local_expn_data.next_index(); - data.orig_id = Some(expn_id.as_u32()); hygiene_data.local_expn_data.push(Some(data)); let _eid = hygiene_data.local_expn_hashes.push(hash); debug_assert_eq!(expn_id, _eid); @@ -1244,9 +1222,8 @@ pub fn register_local_expn_id(mut data: ExpnData, hash: ExpnHash) -> ExpnId { } /// Register an expansion which has been decoded from the metadata of a foreign crate. -pub fn register_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { - let expn_id = - ExpnId { krate: data.krate, local_id: ExpnIndex::from_u32(data.orig_id.unwrap()) }; +pub fn register_expn_id(local_id: ExpnIndex, data: ExpnData, hash: ExpnHash) -> ExpnId { + let expn_id = ExpnId { krate: data.krate, local_id }; HygieneData::with(|hygiene_data| { let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data); debug_assert!(_old_data.is_none()); @@ -1284,9 +1261,8 @@ pub fn decode_expn_id( // other ExpnIds let (expn_data, hash) = decode_data(expn_id); debug_assert_eq!(krate, expn_data.krate); - debug_assert_eq!(Some(index.as_u32()), expn_data.orig_id); - register_expn_id(expn_data, hash) + register_expn_id(index, expn_data, hash) } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` From 41c1f39fa8317fc16779ceda7536fe93f1c89c34 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 20:06:26 +0200 Subject: [PATCH 27/52] Drop ExpnData::krate. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 29 +++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a3f8c7e771b85..8bdd4313de4c3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1653,7 +1653,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; let data = self.root.expn_data.get(self, index).unwrap().decode(self); - rustc_span::hygiene::register_expn_id(index, data, hash) + rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash) } /// Imports the source_map from an external crate into the source_map of the crate diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 32149f1550e30..49ad40fdf4d5b 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -184,7 +184,6 @@ impl LocalExpnId { HygieneData::with(|data| { let old_expn_data = &mut data.local_expn_data[self]; assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); - debug_assert_eq!(expn_data.krate, LOCAL_CRATE); *old_expn_data = Some(expn_data); }); update_disambiguator(self, ctx) @@ -337,11 +336,7 @@ impl HygieneData { } fn fresh_expn(&mut self, expn_data: Option) -> LocalExpnId { - if let Some(data) = &expn_data { - debug_assert_eq!(data.krate, LOCAL_CRATE); - } - let expn_id = self.local_expn_data.next_index(); - self.local_expn_data.push(expn_data); + let expn_id = self.local_expn_data.push(expn_data); let _eid = self.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); debug_assert_eq!(expn_id, _eid); expn_id @@ -873,12 +868,6 @@ pub struct ExpnData { /// call_site span would have its own ExpnData, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// The crate that originally created this `ExpnData`. During - /// metadata serialization, we only encode `ExpnData`s that were - /// created locally - when our serialized metadata is decoded, - /// foreign `ExpnId`s will have their `ExpnData` looked up - /// from the crate specified by `Crate - krate: CrateNum, /// Used to force two `ExpnData`s to have different `Fingerprint`s. /// Due to macro expansion, it's possible to end up with two `ExpnId`s /// that have identical `ExpnData`s. This violates the contract of `HashStable` @@ -944,7 +933,6 @@ impl ExpnData { edition, macro_def_id, parent_module, - krate: LOCAL_CRATE, disambiguator: 0, } } @@ -968,7 +956,6 @@ impl ExpnData { edition, macro_def_id, parent_module, - krate: LOCAL_CRATE, disambiguator: 0, } } @@ -1222,8 +1209,13 @@ pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { } /// Register an expansion which has been decoded from the metadata of a foreign crate. -pub fn register_expn_id(local_id: ExpnIndex, data: ExpnData, hash: ExpnHash) -> ExpnId { - let expn_id = ExpnId { krate: data.krate, local_id }; +pub fn register_expn_id( + krate: CrateNum, + local_id: ExpnIndex, + data: ExpnData, + hash: ExpnHash, +) -> ExpnId { + let expn_id = ExpnId { krate, local_id }; HygieneData::with(|hygiene_data| { let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data); debug_assert!(_old_data.is_none()); @@ -1260,9 +1252,8 @@ pub fn decode_expn_id( // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds let (expn_data, hash) = decode_data(expn_id); - debug_assert_eq!(krate, expn_data.krate); - register_expn_id(index, expn_data, hash) + register_expn_id(krate, index, expn_data, hash) } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` @@ -1420,7 +1411,7 @@ impl Decodable for SyntaxContext { /// This method is called only when an `ExpnData` is first associated /// with an `ExpnId` (when the `ExpnId` is initially constructed, or via /// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized -/// from another crate's metadata - since `ExpnData` includes a `krate` field, +/// from another crate's metadata - since `ExpnHash` includes the stable crate id, /// collisions are only possible between `ExpnId`s within the same crate. fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { let mut expn_data = expn_id.expn_data(); From a51b131fd186ffef240835e18eae3a73501f3090 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jun 2021 21:30:20 +0200 Subject: [PATCH 28/52] Always hash spans in expn. --- compiler/rustc_middle/src/ty/query/on_disk_cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 03e3ca5ec6b8b..c4847ea16c562 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -835,7 +835,7 @@ impl<'a, 'tcx> Decodable> for ExpnId { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; let mut hcx = decoder.tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); - expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); + hcx.while_hashing_spans(true, |hcx| expn_id.expn_data().hash_stable(hcx, &mut hasher)); let local_hash: u64 = hasher.finish(); debug_assert_eq!(hash.local_hash(), local_hash); } From 0f8573e57b62576e4acb8fa0d74346cc82645ee0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 12 Jul 2021 16:56:13 +0200 Subject: [PATCH 29/52] Pass ExpnData by reference. --- compiler/rustc_middle/src/ty/query/on_disk_cache.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index c4847ea16c562..0ac80ebd6367b 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -372,7 +372,7 @@ impl<'sess> OnDiskCache<'sess> { |encoder, expn_id, data, hash| -> FileEncodeResult { if expn_id.krate == LOCAL_CRATE { let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, &data)?; + encoder.encode_tagged(TAG_EXPN_DATA, data)?; expn_data.insert(hash, pos); } else { foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 49ad40fdf4d5b..b4adf2d46bbcd 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1142,7 +1142,7 @@ impl HygieneEncodeContext { &self, encoder: &mut T, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>, - mut encode_expn: impl FnMut(&mut T, ExpnId, ExpnData, ExpnHash) -> Result<(), R>, + mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash) -> Result<(), R>, ) -> Result<(), R> { // When we serialize a `SyntaxContextData`, we may end up serializing // a `SyntaxContext` that we haven't seen before @@ -1344,7 +1344,7 @@ fn for_all_ctxts_in Resul fn for_all_expns_in( expns: impl Iterator, - mut f: impl FnMut(ExpnId, ExpnData, ExpnHash) -> Result<(), E>, + mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash) -> Result<(), E>, ) -> Result<(), E> { let all_data: Vec<_> = HygieneData::with(|data| { expns @@ -1352,7 +1352,7 @@ fn for_all_expns_in( .collect() }); for (expn, data, hash) in all_data.into_iter() { - f(expn, data, hash)?; + f(expn, &data, hash)?; } Ok(()) } From dddaa6d06801955dcbb7b1d1094932383ff36853 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 15 Jul 2021 13:34:33 +0200 Subject: [PATCH 30/52] Rename expn_info -> expn_data. --- compiler/rustc_span/src/hygiene.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b4adf2d46bbcd..c020375fab04b 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -579,19 +579,19 @@ pub fn debug_hygiene_data(verbose: bool) -> String { } else { let mut s = String::from(""); s.push_str("Expansions:"); - let mut debug_expn_data = |(id, expn_info): (&ExpnId, &ExpnData)| { + let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| { s.push_str(&format!( "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", id, - expn_info.parent, - expn_info.call_site.ctxt(), - expn_info.def_site.ctxt(), - expn_info.kind, + expn_data.parent, + expn_data.call_site.ctxt(), + expn_data.def_site.ctxt(), + expn_data.kind, )) }; - data.local_expn_data.iter_enumerated().for_each(|(id, expn_info)| { - let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); - debug_expn_data((&id.to_expn_id(), expn_info)) + data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| { + let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); + debug_expn_data((&id.to_expn_id(), expn_data)) }); data.foreign_expn_data.iter().for_each(debug_expn_data); s.push_str("\n\nSyntaxContexts:"); From b35ceeeec706e957ee46166e0a8b6d912ac215a3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 15 Jul 2021 13:45:38 +0200 Subject: [PATCH 31/52] Simplify Expn creation. --- compiler/rustc_span/src/hygiene.rs | 52 ++++++++++++++---------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c020375fab04b..cb3a08439d129 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -153,14 +153,25 @@ impl LocalExpnId { } pub fn fresh_empty() -> LocalExpnId { - HygieneData::with(|data| data.fresh_expn(None)) + HygieneData::with(|data| { + let expn_id = data.local_expn_data.push(None); + let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); + debug_assert_eq!(expn_id, _eid); + expn_id + }) } - pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId { + pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId { debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); - let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data))); - update_disambiguator(expn_id, ctx); - expn_id + let expn_hash = update_disambiguator(&mut expn_data, ctx); + HygieneData::with(|data| { + let expn_id = data.local_expn_data.push(Some(expn_data)); + let _eid = data.local_expn_hashes.push(expn_hash); + debug_assert_eq!(expn_id, _eid); + let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id()); + debug_assert!(_old_id.is_none()); + expn_id + }) } #[inline] @@ -179,14 +190,18 @@ impl LocalExpnId { } #[inline] - pub fn set_expn_data(self, expn_data: ExpnData, ctx: impl HashStableContext) { + pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); + let expn_hash = update_disambiguator(&mut expn_data, ctx); HygieneData::with(|data| { let old_expn_data = &mut data.local_expn_data[self]; assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); *old_expn_data = Some(expn_data); + debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO); + data.local_expn_hashes[self] = expn_hash; + let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id()); + debug_assert!(_old_id.is_none()); }); - update_disambiguator(self, ctx) } #[inline] @@ -335,13 +350,6 @@ impl HygieneData { with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) } - fn fresh_expn(&mut self, expn_data: Option) -> LocalExpnId { - let expn_id = self.local_expn_data.push(expn_data); - let _eid = self.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); - debug_assert_eq!(expn_id, _eid); - expn_id - } - #[inline] fn local_expn_hash(&self, expn_id: LocalExpnId) -> ExpnHash { self.local_expn_hashes[expn_id] @@ -1413,8 +1421,7 @@ impl Decodable for SyntaxContext { /// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized /// from another crate's metadata - since `ExpnHash` includes the stable crate id, /// collisions are only possible between `ExpnId`s within the same crate. -fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { - let mut expn_data = expn_id.expn_data(); +fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash { // This disambiguator should not have been set yet. assert_eq!( expn_data.disambiguator, 0, @@ -1433,8 +1440,7 @@ fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { }); if disambiguator != 0 { - debug!("Set disambiguator for {:?} (hash {:?})", expn_id, expn_hash); - debug!("expn_data = {:?}", expn_data); + debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash); expn_data.disambiguator = disambiguator; expn_hash = expn_data.hash_expn(&mut ctx); @@ -1450,15 +1456,7 @@ fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) { }); } - let expn_hash = - ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash); - HygieneData::with(|data| { - data.local_expn_data[expn_id].as_mut().unwrap().disambiguator = disambiguator; - debug_assert_eq!(data.local_expn_hashes[expn_id].0, Fingerprint::ZERO); - data.local_expn_hashes[expn_id] = expn_hash; - let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id()); - debug_assert!(_old_id.is_none()); - }); + ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash) } impl HashStable for SyntaxContext { From d954a8ee8e76fc69ddc6a3e785a6e986a2e08e52 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 16 Jul 2021 16:23:42 -0400 Subject: [PATCH 32/52] Some perf optimizations and logging --- .../rustc_data_structures/src/obligation_forest/mod.rs | 2 ++ compiler/rustc_infer/src/infer/type_variable.rs | 1 + compiler/rustc_trait_selection/src/traits/fulfill.rs | 3 +-- compiler/rustc_trait_selection/src/traits/project.rs | 10 ++++++---- .../src/traits/query/normalize.rs | 2 +- .../rustc_trait_selection/src/traits/select/mod.rs | 10 +++++++--- compiler/rustc_trait_selection/src/traits/wf.rs | 1 + compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 1 + compiler/rustc_typeck/src/check/inherited.rs | 1 + compiler/rustc_typeck/src/check/wfcheck.rs | 7 +++---- 10 files changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 05b1a85381f45..25b7a84b3a069 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -418,6 +418,7 @@ impl ObligationForest { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). + #[inline(never)] pub fn process_obligations(&mut self, processor: &mut P) -> OUT where P: ObligationProcessor, @@ -671,6 +672,7 @@ impl ObligationForest { self.reused_node_vec = node_rewrites; } + #[inline(never)] fn apply_rewrites(&mut self, node_rewrites: &[usize]) { let orig_nodes_len = node_rewrites.len(); diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 683c1df783e63..13b78b26af424 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -400,6 +400,7 @@ impl<'tcx> From for TyVidEqKey<'tcx> { impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { type Value = TypeVariableValue<'tcx>; + #[inline(always)] fn index(&self) -> u32 { self.vid.index } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 21ed586ab560b..dfe2909498d18 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -167,6 +167,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// `SomeTrait` or a where-clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. + #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))] fn normalize_projection_type( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -174,8 +175,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, ) -> Ty<'tcx> { - debug!(?projection_ty, "normalize_projection_type"); - debug_assert!(!projection_ty.has_escaping_bound_vars()); // FIXME(#20304) -- cache diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 98fde3707f70e..f342042bd11b5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -273,7 +273,7 @@ where Normalized { value, obligations } } -#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -285,6 +285,7 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( where T: TypeFoldable<'tcx>, { + debug!(obligations.len = obligations.len()); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); let result = ensure_sufficient_stack(|| normalizer.fold(value)); debug!(?result, obligations.len = normalizer.obligations.len()); @@ -314,6 +315,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { fn fold>(&mut self, value: T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); + debug!(?value); assert!( !value.has_escaping_bound_vars(), @@ -825,7 +827,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); match cache_result { - Ok(()) => {} + Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue // to do so until some type in the key changes (and we know it @@ -852,6 +854,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { + debug!("recur cache"); return Err(InProgress); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { @@ -1058,12 +1061,11 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized +#[tracing::instrument(level = "info", skip(selcx))] fn project_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, ) -> Result, ProjectionTyError<'tcx>> { - debug!(?obligation, "project_type"); - if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); // This should really be an immediate error, but some existing code diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 94539eda0f89e..b13b1a6264c73 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -65,7 +65,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { }; let result = value.fold_with(&mut normalizer); - debug!( + info!( "normalize::<{}>: result={:?} with {} obligations", std::any::type_name::(), result, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f17965f6f6be6..564c63ef30cb6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1865,12 +1865,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn match_impl( &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Result>, ()> { - debug!(?impl_def_id, ?obligation, "match_impl"); let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first @@ -1888,6 +1888,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + debug!(?impl_trait_ref); + let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -1915,7 +1917,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - debug!(?impl_substs, "match_impl: success"); + debug!(?impl_substs, ?nested_obligations, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } @@ -2068,6 +2070,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default /// impl. + #[tracing::instrument(level = "debug", skip(self, cause, param_env))] fn impl_or_trait_obligations( &mut self, cause: ObligationCause<'tcx>, @@ -2076,7 +2079,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait ) -> Vec> { - debug!(?def_id, "impl_or_trait_obligations"); let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2094,9 +2096,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `$1: Copy`, so we must ensure the obligations are emitted in // that order. let predicates = tcx.predicates_of(def_id); + debug!(?predicates); assert_eq!(predicates.parent, None); let mut obligations = Vec::with_capacity(predicates.predicates.len()); for (predicate, _) in predicates.predicates { + debug!(?predicate); let predicate = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9ee6eeb1fd5ed..27c8e00c5596c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -85,6 +85,7 @@ pub fn trait_obligations<'a, 'tcx>( let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item }; wf.compute_trait_ref(trait_ref, Elaborate::All); + debug!(obligations = ?wf.out); wf.normalize() } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e045c30e0de6b..4ed07ba358de3 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1578,6 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Add all the obligations that are required, substituting and normalized appropriately. + #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))] fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 237861f1dd248..7e43e36fe55c6 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -179,6 +179,7 @@ impl Inherited<'a, 'tcx> { T: TypeFoldable<'tcx>, { let ok = self.partially_normalize_associated_types_in(cause, param_env, value); + debug!(?ok); self.register_infer_ok_obligations(ok) } } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index bff391eb2d7a8..b24d63917c1cf 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -379,14 +379,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } +#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))] fn check_associated_item( tcx: TyCtxt<'_>, item_id: hir::HirId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - debug!("check_associated_item: {:?}", item_id); - let code = ObligationCauseCode::WellFormed(Some(item_id)); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -650,14 +649,13 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo }); } +#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, ) { - debug!("check_impl: {:?}", item); - for_item(tcx, item).with_fcx(|fcx| { match *ast_trait_ref { Some(ref ast_trait_ref) => { @@ -675,6 +673,7 @@ fn check_impl<'tcx>( ast_trait_ref.path.span, Some(item), ); + debug!(?obligations); for obligation in obligations { fcx.register_predicate(obligation); } From fa839b1194a401c77a5fadba0a2b351870ea4683 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 16 Jul 2021 16:23:42 -0400 Subject: [PATCH 33/52] Add needs_normalization --- .../src/traits/project.rs | 20 +++++++++++++++++-- .../src/traits/query/normalize.rs | 5 +++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index f342042bd11b5..d1ab9fa025ed6 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -293,6 +293,18 @@ where result } +pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool { + match reveal { + Reveal::UserFacing => value + .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), + Reveal::All => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_OPAQUE + | ty::TypeFlags::HAS_CT_PROJECTION, + ), + } +} + struct AssocTypeNormalizer<'a, 'b, 'tcx> { selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -323,7 +335,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { value ); - if !value.has_projections() { value } else { value.fold_with(self) } + if !needs_normalization(&value, self.param_env.reveal()) { + value + } else { + value.fold_with(self) + } } } @@ -343,7 +359,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { + if !needs_normalization(&ty, self.param_env.reveal()) { return ty; } // We don't want to normalize associated types that occur inside of region diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b13b1a6264c73..d65a378b1edec 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,6 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::needs_normalization; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -49,7 +50,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { value, self.param_env, ); - if !value.has_projections() { + if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); } @@ -112,7 +113,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { #[instrument(level = "debug", skip(self))] fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { + if !needs_normalization(&ty, self.param_env.reveal()) { return ty; } From ddd544856ecd181ee02490d12f723be549d3ecb3 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 14 Jul 2021 18:24:12 -0500 Subject: [PATCH 34/52] Compute a better `lint_node_id` during expansion When we need to emit a lint at a macro invocation, we currently use the `NodeId` of its parent definition (e.g. the enclosing function). This means that any `#[allow]` / `#[deny]` attributes placed 'closer' to the macro (e.g. on an enclosing block or statement) will have no effect. This commit computes a better `lint_node_id` in `InvocationCollector`. When we visit/flat_map an AST node, we assign it a `NodeId` (earlier than we normally would), and store than `NodeId` in current `ExpansionData`. When we collect a macro invocation, the current `lint_node_id` gets cloned along with our `ExpansionData`, allowing it to be used if we need to emit a lint later on. This improves the handling of `#[allow]` / `#[deny]` for `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` and some `asm!`-related lints. The 'legacy derive helpers' lint retains its current behavior (I've inlined the now-removed `lint_node_id` function), since there isn't an `ExpansionData` readily available. --- compiler/rustc_builtin_macros/src/asm.rs | 4 +- .../rustc_builtin_macros/src/source_util.rs | 2 +- compiler/rustc_expand/src/base.rs | 6 +- compiler/rustc_expand/src/expand.rs | 100 ++++++++++++++---- compiler/rustc_expand/src/mbe/macro_rules.rs | 3 +- compiler/rustc_lint_defs/src/lib.rs | 4 +- compiler/rustc_resolve/src/macros.rs | 16 ++- src/test/ui/asm/inline-syntax.x86_64.stderr | 16 +-- .../semicolon-in-expressions-from-macros.rs | 24 +++-- ...emicolon-in-expressions-from-macros.stderr | 29 +++-- 10 files changed, 139 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 97e07d52cc31a..ff13f0d4e4207 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -455,7 +455,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option, args: AsmArgs) -> Option( } } - Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) }) + Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id }) } // include_str! : read the given file, insert it as a literal string expr diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 497be2d931872..03ded6465d079 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -869,9 +869,6 @@ pub trait ResolverExpand { fn check_unused_macros(&mut self); - /// Some parent node that is close enough to the given macro call. - fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId; - // Resolver interfaces for specific built-in macros. /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool; @@ -926,6 +923,8 @@ pub struct ExpansionData { pub module: Rc, pub dir_ownership: DirOwnership, pub prior_type_ascription: Option<(Span, bool)>, + /// Some parent node that is close to this macro call + pub lint_node_id: NodeId, } type OnExternModLoaded<'a> = @@ -971,6 +970,7 @@ impl<'a> ExtCtxt<'a> { module: Default::default(), dir_ownership: DirOwnership::Owned { relative: None }, prior_type_ascription: None, + lint_node_id: ast::CRATE_NODE_ID, }, force_mode: false, expansions: FxHashMap::default(), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index b9d4096241142..f79e9648ab66e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1098,6 +1098,41 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } +/// Wraps a call to `noop_visit_*` / `noop_flat_map_*` +/// This method assigns a `NodeId`, and sets that `NodeId` +/// as our current 'lint node id'. If a macro call is found +/// inside this AST node, we will use this AST node's `NodeId` +/// to emit lints associated with that macro (allowing +/// `#[allow]` / `#[deny]` to be applied close to +/// the macro invocation). +/// +/// Do *not* call this for a macro AST node +/// (e.g. `ExprKind::MacCall`) - we cannot emit lints +/// at these AST nodes, since they are removed and +/// replaced with the result of macro expansion. +/// +/// All other `NodeId`s are assigned by `visit_id`. +/// * `self` is the 'self' parameter for the current method, +/// * `id` is a mutable reference to the `NodeId` field +/// of the current AST node. +/// * `closure` is a closure that executes the +/// `noop_visit_*` / `noop_flat_map_*` method +/// for the current AST node. +macro_rules! assign_id { + ($self:ident, $id:expr, $closure:expr) => {{ + let old_id = $self.cx.current_expansion.lint_node_id; + if $self.monotonic { + debug_assert_eq!(*$id, ast::DUMMY_NODE_ID); + let new_id = $self.cx.resolver.next_node_id(); + *$id = new_id; + $self.cx.current_expansion.lint_node_id = new_id; + } + let ret = ($closure)(); + $self.cx.current_expansion.lint_node_id = old_id; + ret + }}; +} + impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_expr(&mut self, expr: &mut P) { self.cfg.configure_expr(expr); @@ -1118,7 +1153,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() } else { - ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); + assign_id!(self, &mut expr.id, || { + ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); + }); expr } }); @@ -1133,7 +1170,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_arms(); } - noop_flat_map_arm(arm, self) + assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self)) } fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { @@ -1145,7 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_expr_fields(); } - noop_flat_map_expr_field(field, self) + assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self)) } fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { @@ -1157,7 +1194,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_pat_fields(); } - noop_flat_map_pat_field(fp, self) + assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self)) } fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { @@ -1169,7 +1206,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_params(); } - noop_flat_map_param(p, self) + assign_id!(self, &mut p.id, || noop_flat_map_param(p, self)) } fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { @@ -1181,7 +1218,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_field_defs(); } - noop_flat_map_field_def(sf, self) + assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self)) } fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { @@ -1193,7 +1230,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_variants(); } - noop_flat_map_variant(variant, self) + assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self)) } fn filter_map_expr(&mut self, expr: P) -> Option> { @@ -1214,9 +1251,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_opt_expr() .map(|expr| expr.into_inner()) } else { - Some({ - noop_visit_expr(&mut expr, self); - expr + assign_id!(self, &mut expr.id, || { + Some({ + noop_visit_expr(&mut expr, self); + expr + }) }) } }) @@ -1225,7 +1264,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_pat(&mut self, pat: &mut P) { match pat.kind { PatKind::MacCall(_) => {} - _ => return noop_visit_pat(pat, self), + _ => { + return assign_id!(self, &mut pat.id, || noop_visit_pat(pat, self)); + } } visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { @@ -1278,7 +1319,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { &mut self.cx.current_expansion.dir_ownership, DirOwnership::UnownedViaBlock, ); - noop_visit_block(block, self); + assign_id!(self, &mut block.id, || noop_visit_block(block, self)); self.cx.current_expansion.dir_ownership = orig_dir_ownership; } @@ -1377,7 +1418,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let orig_dir_ownership = mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); - let result = noop_flat_map_item(item, self); + let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)); // Restore the module info. self.cx.current_expansion.dir_ownership = orig_dir_ownership; @@ -1387,7 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } _ => { item.attrs = attrs; - noop_flat_map_item(item, self) + // The crate root is special - don't assign an ID to it. + if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) { + assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)) + } else { + noop_flat_map_item(item, self) + } } } } @@ -1411,7 +1457,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_assoc_item(item, self), + _ => { + assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) + } } } @@ -1434,14 +1482,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_assoc_item(item, self), + _ => { + assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) + } } } fn visit_ty(&mut self, ty: &mut P) { match ty.kind { ast::TyKind::MacCall(_) => {} - _ => return noop_visit_ty(ty, self), + _ => return assign_id!(self, &mut ty.id, || noop_visit_ty(ty, self)), }; visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { @@ -1478,7 +1528,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_foreign_item(foreign_item, self), + _ => { + assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item( + foreign_item, + self + )) + } } } @@ -1498,13 +1553,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_generic_params(); } - noop_flat_map_generic_param(param, self) + assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self)) } fn visit_id(&mut self, id: &mut ast::NodeId) { - if self.monotonic { - debug_assert_eq!(*id, ast::DUMMY_NODE_ID); - *id = self.cx.resolver.next_node_id() + // We may have already assigned a `NodeId` + // by calling `assign_id` + if self.monotonic && *id == ast::DUMMY_NODE_ID { + *id = self.cx.resolver.next_node_id(); } } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8b68c94e61a38..7f985af364d7d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -289,7 +289,6 @@ fn generic_extension<'cx>( let mut p = Parser::new(sess, tts, false, None); p.last_type_ascription = cx.current_expansion.prior_type_ascription; - let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. @@ -301,7 +300,7 @@ fn generic_extension<'cx>( // macro leaves unparsed tokens. site_span: sp, macro_ident: name, - lint_node_id, + lint_node_id: cx.current_expansion.lint_node_id, arm_span, }); } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 001198226d9a3..4d85bf6b499d9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -274,7 +274,7 @@ impl ToStableHashKey for LintId { } // Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum ExternDepSpec { Json(Json), Raw(String), @@ -282,7 +282,7 @@ pub enum ExternDepSpec { // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum BuiltinLintDiagnostics { Normal, BareTraitObject(Span, /* is_global */ bool), diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 86f271fdeceb8..b2a8aa0ceccaa 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -281,7 +281,7 @@ impl<'a> ResolverExpand for Resolver<'a> { // Derives are not included when `invocations` are collected, so we have to add them here. let parent_scope = &ParentScope { derives, ..parent_scope }; let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion(); - let node_id = self.lint_node_id(eager_expansion_root); + let node_id = invoc.expansion_data.lint_node_id; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -348,14 +348,6 @@ impl<'a> ResolverExpand for Resolver<'a> { } } - fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId { - // FIXME - make this more precise. This currently returns the NodeId of the - // nearest closing item - we should try to return the closest parent of the ExpnId - self.invocation_parents - .get(&expn_id) - .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]) - } - fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool { self.containers_deriving_copy.contains(&expn_id) } @@ -1105,9 +1097,13 @@ impl<'a> Resolver<'a> { let seg = Segment::from_ident(ident); check_consistency(self, &[seg], ident.span, kind, initial_res, res); if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) { + let node_id = self + .invocation_parents + .get(&parent_scope.expansion) + .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]); self.lint_buffer.buffer_lint_with_diagnostic( LEGACY_DERIVE_HELPERS, - self.lint_node_id(parent_scope.expansion), + node_id, ident.span, "derive helper attribute is used before it is introduced", BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span), diff --git a/src/test/ui/asm/inline-syntax.x86_64.stderr b/src/test/ui/asm/inline-syntax.x86_64.stderr index dcbc17bb26089..a0e2a5ea0ef97 100644 --- a/src/test/ui/asm/inline-syntax.x86_64.stderr +++ b/src/test/ui/asm/inline-syntax.x86_64.stderr @@ -1,16 +1,10 @@ -warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:57:14 - | -LL | global_asm!(".intel_syntax noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(bad_asm_style)]` on by default - warning: avoid using `.intel_syntax`, Intel syntax is the default --> $DIR/inline-syntax.rs:31:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default --> $DIR/inline-syntax.rs:34:15 @@ -42,5 +36,11 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:57:14 + | +LL | global_asm!(".intel_syntax noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^ + warning: 7 warnings emitted diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs index 0bbd7dc6c8a7a..fff380934e8e9 100644 --- a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs @@ -1,14 +1,17 @@ // check-pass // edition:2018 +#![feature(stmt_expr_attributes)] #![warn(semicolon_in_expressions_from_macros)] #[allow(dead_code)] macro_rules! foo { ($val:ident) => { - true; //~ WARN trailing - //~| WARN this was previously - //~| WARN trailing - //~| WARN this was previously + true; //~ WARN trailing semicolon in macro + //~| WARN this was previously accepted + //~| WARN trailing semicolon in macro + //~| WARN this was previously accepted + //~| WARN trailing semicolon in macro + //~| WARN this was previously accepted } } @@ -18,17 +21,14 @@ async fn bar() { } fn main() { - // This `allow` doesn't work #[allow(semicolon_in_expressions_from_macros)] let _ = { foo!(first) }; - // This 'allow' doesn't work either #[allow(semicolon_in_expressions_from_macros)] let _ = foo!(second); - // But this 'allow' does #[allow(semicolon_in_expressions_from_macros)] fn inner() { let _ = foo!(third); @@ -38,4 +38,14 @@ fn main() { async { let _ = foo!(fourth); }; + + let _ = { + foo!(warn_in_block) + }; + + let _ = foo!(warn_in_expr); + + // This `#[allow]` does not work, since the attribute gets dropped + // when we expand the macro + let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); } diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr index 111ebea61dd12..c00c3d77dcedc 100644 --- a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr @@ -1,14 +1,14 @@ warning: trailing semicolon in macro used in expression position - --> $DIR/semicolon-in-expressions-from-macros.rs:8:13 + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 | LL | true; | ^ ... -LL | foo!(first) - | ----------- in this macro invocation +LL | foo!(warn_in_block) + | ------------------- in this macro invocation | note: the lint level is defined here - --> $DIR/semicolon-in-expressions-from-macros.rs:3:9 + --> $DIR/semicolon-in-expressions-from-macros.rs:4:9 | LL | #![warn(semicolon_in_expressions_from_macros)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,17 +17,30 @@ LL | #![warn(semicolon_in_expressions_from_macros)] = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) warning: trailing semicolon in macro used in expression position - --> $DIR/semicolon-in-expressions-from-macros.rs:8:13 + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 | LL | true; | ^ ... -LL | let _ = foo!(second); - | ------------ in this macro invocation +LL | let _ = foo!(warn_in_expr); + | ------------------ in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 2 warnings emitted +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); + | ------------------------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 3 warnings emitted From 2bd15a25ef24949abbcfe066c04cd2a266410c47 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 14 Jul 2021 20:07:56 -0500 Subject: [PATCH 35/52] Add missing `visit_expr_field` --- compiler/rustc_lint/src/early.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index eb2e495f73d3c..63e2f66f8102b 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -120,6 +120,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } + fn visit_expr_field(&mut self, f: &'a ast::ExprField) { + self.with_lint_attrs(f.id, &f.attrs, |cx| { + ast_visit::walk_expr_field(cx, f); + }) + } + fn visit_stmt(&mut self, s: &'a ast::Stmt) { // Add the statement's lint attributes to our // current state when checking the statement itself. @@ -389,9 +395,15 @@ pub fn check_ast_crate( // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. - for (_id, lints) in buffered.map { + for (id, lints) in buffered.map { for early_lint in lints { - sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); + sess.delay_span_bug( + early_lint.span, + &format!( + "failed to process buffered lint here (dummy = {})", + id == ast::DUMMY_NODE_ID + ), + ); } } } From d6e3c111011f6a270d56fdaf5222b484c4f38d65 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 15 Jul 2021 14:26:27 -0500 Subject: [PATCH 36/52] Add additional missing lint handling logic --- compiler/rustc_expand/src/expand.rs | 9 ++++++++- compiler/rustc_lint/src/early.rs | 6 ++++-- src/test/ui/asm/inline-syntax.x86_64.stderr | 16 ++++++++-------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f79e9648ab66e..208894c3791bb 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -12,7 +12,7 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs}; +use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; @@ -1161,6 +1161,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { }); } + // This is needed in order to set `lint_node_id` for `let` statements + fn visit_local(&mut self, local: &mut P) { + assign_id!(self, &mut local.id, || noop_visit_local(local, self)); + } + fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { let mut arm = configure!(self, arm); @@ -1307,6 +1312,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. + // We don't use `assign_id!` - it will be called when we visit statement's contents + // (e.g. an expression, item, or local) let ast::Stmt { id, kind, span } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 63e2f66f8102b..7a8b731da5c2e 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -210,8 +210,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_arm(&mut self, a: &'a ast::Arm) { - run_early_pass!(self, check_arm, a); - ast_visit::walk_arm(self, a); + self.with_lint_attrs(a.id, &a.attrs, |cx| { + run_early_pass!(cx, check_arm, a); + ast_visit::walk_arm(cx, a); + }) } fn visit_expr_post(&mut self, e: &'a ast::Expr) { diff --git a/src/test/ui/asm/inline-syntax.x86_64.stderr b/src/test/ui/asm/inline-syntax.x86_64.stderr index a0e2a5ea0ef97..dcbc17bb26089 100644 --- a/src/test/ui/asm/inline-syntax.x86_64.stderr +++ b/src/test/ui/asm/inline-syntax.x86_64.stderr @@ -1,10 +1,16 @@ +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:57:14 + | +LL | global_asm!(".intel_syntax noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(bad_asm_style)]` on by default + warning: avoid using `.intel_syntax`, Intel syntax is the default --> $DIR/inline-syntax.rs:31:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default --> $DIR/inline-syntax.rs:34:15 @@ -36,11 +42,5 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ -warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:57:14 - | -LL | global_asm!(".intel_syntax noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^ - warning: 7 warnings emitted From 7ca089c6d2e834ea007d7a62b8bbbe0c880de4a2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 17 Jul 2021 08:22:09 -0500 Subject: [PATCH 37/52] Only use `assign_id!` for ast nodes that support attributes --- compiler/rustc_expand/src/base.rs | 3 +++ compiler/rustc_expand/src/expand.rs | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 03ded6465d079..8c6aef80635cf 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -29,6 +29,9 @@ use std::rc::Rc; crate use rustc_span::hygiene::MacroKind; +// When adding new variants, make sure to +// adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector` +// to use `assign_id!` #[derive(Debug, Clone)] pub enum Annotatable { Item(P), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 208894c3791bb..dcd871c9d2050 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1099,6 +1099,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } /// Wraps a call to `noop_visit_*` / `noop_flat_map_*` +/// for an AST node that supports attributes +/// (see the `Annotatable` enum) /// This method assigns a `NodeId`, and sets that `NodeId` /// as our current 'lint node id'. If a macro call is found /// inside this AST node, we will use this AST node's `NodeId` @@ -1269,9 +1271,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_pat(&mut self, pat: &mut P) { match pat.kind { PatKind::MacCall(_) => {} - _ => { - return assign_id!(self, &mut pat.id, || noop_visit_pat(pat, self)); - } + _ => return noop_visit_pat(pat, self), } visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { @@ -1326,7 +1326,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { &mut self.cx.current_expansion.dir_ownership, DirOwnership::UnownedViaBlock, ); - assign_id!(self, &mut block.id, || noop_visit_block(block, self)); + noop_visit_block(block, self); self.cx.current_expansion.dir_ownership = orig_dir_ownership; } @@ -1498,7 +1498,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_ty(&mut self, ty: &mut P) { match ty.kind { ast::TyKind::MacCall(_) => {} - _ => return assign_id!(self, &mut ty.id, || noop_visit_ty(ty, self)), + _ => return noop_visit_ty(ty, self), }; visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { From 1c1c7949ab6a8d4150b7e645ae4779677e86ebd1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 17 Jul 2021 08:31:13 -0500 Subject: [PATCH 38/52] Add test for `#[allow]` for warnings on attribute macro --- .../proc-macro/auxiliary/call-deprecated.rs | 19 +++++++++++ src/test/ui/proc-macro/call-deprecated.rs | 34 +++++++++++++++++++ src/test/ui/proc-macro/call-deprecated.stderr | 16 +++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/test/ui/proc-macro/auxiliary/call-deprecated.rs create mode 100644 src/test/ui/proc-macro/call-deprecated.rs create mode 100644 src/test/ui/proc-macro/call-deprecated.stderr diff --git a/src/test/ui/proc-macro/auxiliary/call-deprecated.rs b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs new file mode 100644 index 0000000000000..2f484809a5c99 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs @@ -0,0 +1,19 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_attribute] +#[deprecated(since = "1.0.0", note = "test")] +pub fn attr(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +#[deprecated(since = "1.0.0", note = "test")] +pub fn attr_remove(_: TokenStream, _: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/call-deprecated.rs b/src/test/ui/proc-macro/call-deprecated.rs new file mode 100644 index 0000000000000..b92cc23638ae1 --- /dev/null +++ b/src/test/ui/proc-macro/call-deprecated.rs @@ -0,0 +1,34 @@ +// check-pass +// aux-build:call-deprecated.rs + +extern crate call_deprecated; + +// These first two `#[allow(deprecated)]` attributes +// do nothing, since the AST nodes for `First` and `Second` +// haven't been been assigned a `NodeId`. +// See #63221 for a discussion about how we should +// handle the interaction of 'inert' attributes and +// proc-macro attributes. + +#[allow(deprecated)] +#[call_deprecated::attr] //~ WARN use of deprecated macro +struct First; + +#[allow(deprecated)] +#[call_deprecated::attr_remove] //~ WARN use of deprecated macro +struct Second; + +#[allow(deprecated)] +mod bar { + #[allow(deprecated)] + #[call_deprecated::attr] + struct Third; + + #[allow(deprecated)] + #[call_deprecated::attr_remove] + struct Fourth; +} + + +fn main() { +} diff --git a/src/test/ui/proc-macro/call-deprecated.stderr b/src/test/ui/proc-macro/call-deprecated.stderr new file mode 100644 index 0000000000000..3506f9a16a3c4 --- /dev/null +++ b/src/test/ui/proc-macro/call-deprecated.stderr @@ -0,0 +1,16 @@ +warning: use of deprecated macro `call_deprecated::attr`: test + --> $DIR/call-deprecated.rs:14:3 + | +LL | #[call_deprecated::attr] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated macro `call_deprecated::attr_remove`: test + --> $DIR/call-deprecated.rs:18:3 + | +LL | #[call_deprecated::attr_remove] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + From 81241cbf3ae39db6188b7965b34e444f48e7ebbd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 28 Jun 2021 21:12:01 +0200 Subject: [PATCH 39/52] Move OnDiskCache to rustc_query_impl. --- Cargo.lock | 4 + .../rustc_incremental/src/persist/load.rs | 10 +- compiler/rustc_interface/src/interface.rs | 3 +- compiler/rustc_interface/src/passes.rs | 8 +- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 60 ++++- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../src/ty/{query/mod.rs => query.rs} | 25 +-- compiler/rustc_query_impl/Cargo.toml | 6 +- compiler/rustc_query_impl/src/lib.rs | 10 +- .../src}/on_disk_cache.rs | 210 ++++++++---------- compiler/rustc_query_impl/src/plumbing.rs | 76 ++++--- 14 files changed, 226 insertions(+), 197 deletions(-) rename compiler/rustc_middle/src/ty/{query/mod.rs => query.rs} (93%) rename compiler/{rustc_middle/src/ty/query => rustc_query_impl/src}/on_disk_cache.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index b261a00f4f3ab..753853e6acde4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4242,12 +4242,16 @@ version = "0.0.0" dependencies = [ "measureme", "rustc-rayon-core", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_serialize", + "rustc_session", "rustc_span", "tracing", ] diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ee62089b23760..437d5596447d7 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; -use rustc_middle::ty::query::OnDiskCache; +use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; use rustc_session::Session; @@ -198,7 +198,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { /// If we are not in incremental compilation mode, returns `None`. /// Otherwise, tries to load the query result cache from disk, /// creating an empty cache if it could not be loaded. -pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> { +pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option { if sess.opts.incremental.is_none() { return None; } @@ -210,9 +210,7 @@ pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> &query_cache_path(sess), sess.is_nightly_build(), ) { - LoadResult::Ok { data: (bytes, start_pos) } => { - Some(OnDiskCache::new(sess, bytes, start_pos)) - } - _ => Some(OnDiskCache::new_empty(sess.source_map())), + LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)), + _ => Some(C::new_empty(sess.source_map())), } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 086c49c73972f..8393826aa1285 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -12,6 +12,7 @@ use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; use rustc_parse::new_parser_from_source_str; +use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; use rustc_session::lint; @@ -233,7 +234,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames) + QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 958a4ab68020a..5db027fb5b473 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -26,7 +26,7 @@ use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_query_impl::Queries as TcxQueries; +use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_serialize::json; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; @@ -819,7 +819,9 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } - let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers)); + let queries = queries.get_or_init(|| { + TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) + }); let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(move || { @@ -830,7 +832,7 @@ pub fn create_global_ctxt<'tcx>( resolver_outputs, krate, dep_graph, - query_result_on_disk_cache, + queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), &crate_name, outputs, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 291e7ef045e4f..dcd36d61bc6a0 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -367,7 +367,7 @@ fn add_query_description_impl( tcx: QueryCtxt<'tcx>, id: SerializedDepNodeIndex ) -> Option { - tcx.on_disk_cache.as_ref()?.try_load_query_result(*tcx, id) + tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id) } } }; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 70b3efa1d1690..5373169bda7ab 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -131,7 +131,10 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { impl CStore { pub fn from_tcx(tcx: TyCtxt<'_>) -> &CStore { - tcx.cstore_as_any().downcast_ref::().expect("`tcx.cstore` is not a `CStore`") + tcx.cstore_untracked() + .as_any() + .downcast_ref::() + .expect("`tcx.cstore` is not a `CStore`") } fn alloc_new_crate_num(&mut self) -> CrateNum { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1651853a55205..cb99ae19ee72e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -724,7 +724,7 @@ rustc_queries! { cache_on_disk_if { true } load_cached(tcx, id) { let typeck_results: Option> = tcx - .on_disk_cache.as_ref() + .on_disk_cache().as_ref() .and_then(|c| c.try_load_query_result(*tcx, id)); typeck_results.map(|x| &*tcx.arena.alloc(x)) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f52686c9b5f2e..47cc328f6c8bb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,7 +1,7 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::DepGraph; +use crate::dep_graph::{DepGraph, DepNode}; use crate::hir::place::Place as HirPlace; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; @@ -14,7 +14,7 @@ use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::thir::Thir; use crate::traits; -use crate::ty::query::{self, OnDiskCache, TyCtxtAt}; +use crate::ty::query::{self, TyCtxtAt}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; use crate::ty::{ @@ -52,8 +52,8 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; -use rustc_span::def_id::StableCrateId; -use rustc_span::source_map::MultiSpan; +use rustc_span::def_id::{DefPathHash, StableCrateId}; +use rustc_span::source_map::{MultiSpan, SourceMap}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; @@ -71,6 +71,40 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; +pub trait OnDiskCache<'tcx> { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + fn new(sess: &'tcx Session, data: Vec, start_pos: usize) -> Self + where + Self: Sized; + + fn new_empty(source_map: &'tcx SourceMap) -> Self + where + Self: Sized; + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + fn def_path_hash_to_def_id( + &self, + tcx: TyCtxt<'tcx>, + def_path_hash: DefPathHash, + ) -> Option; + + /// If the given `dep_node`'s hash still exists in the current compilation, + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. + /// + /// Normally, `store_foreign_def_id_hash` can be called directly by + /// the dependency graph when we construct a `DepNode`. However, + /// when we re-use a deserialized `DepNode` from the previous compilation + /// session, we only have the `DefPathHash` available. This method is used + /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written + /// out for usage in the next compilation session. + fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode); + fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash); + + fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; +} + /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s /// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -993,7 +1027,7 @@ pub struct GlobalCtxt<'tcx> { /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. /// This is `None` if we are not incremental compilation mode - pub on_disk_cache: Option>, + pub on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, @@ -1141,7 +1175,7 @@ impl<'tcx> TyCtxt<'tcx> { resolutions: ty::ResolverOutputs, krate: &'tcx hir::Crate<'tcx>, dep_graph: DepGraph, - on_disk_cache: Option>, + on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, crate_name: &str, output_filenames: OutputFilenames, @@ -1308,10 +1342,16 @@ impl<'tcx> TyCtxt<'tcx> { self.untracked_resolutions.cstore.encode_metadata(self) } - // Note that this is *untracked* and should only be used within the query - // system if the result is otherwise tracked through queries - pub fn cstore_as_any(self) -> &'tcx dyn Any { - self.untracked_resolutions.cstore.as_any() + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn { + &*self.untracked_resolutions.cstore + } + + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions { + &self.untracked_resolutions.definitions } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bfc942e6f10ff..a6aff42479069 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -59,7 +59,7 @@ pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Uneval pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, - Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, + Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; pub use self::instance::{Instance, InstanceDef}; pub use self::list::List; diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query.rs similarity index 93% rename from compiler/rustc_middle/src/ty/query/mod.rs rename to compiler/rustc_middle/src/ty/query.rs index 2ed9ede8951c9..38ed82933fe94 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -38,14 +38,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ErrorReported, Handler}; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; -use rustc_serialize::opaque; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; @@ -63,9 +62,6 @@ use std::sync::Arc; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -pub mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - #[derive(Copy, Clone)] pub struct TyCtxtAt<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -235,28 +231,13 @@ macro_rules! define_callbacks { } pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; + #[cfg(parallel_compiler)] unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult; - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>); - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool; - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize; - $($(#[$attr])* fn $name( &'tcx self, diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 5be06dfdc7797..6a1768b92dbbb 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -11,10 +11,14 @@ doctest = false measureme = "9.0.0" rustc-rayon-core = "0.3.1" tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } -rustc_span = { path = "../rustc_span" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 1d831affd1dee..5022bf265328a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -1,12 +1,16 @@ //! Support for serializing the dep-graph and reloading it. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(min_specialization)] +#![feature(once_cell)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#[macro_use] +extern crate rustc_macros; #[macro_use] extern crate rustc_middle; #[macro_use] @@ -14,13 +18,12 @@ extern crate tracing; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{DiagnosticBuilder, Handler}; +use rustc_errors::DiagnosticBuilder; use rustc_middle::dep_graph; use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_serialize::opaque; use rustc_span::Span; #[macro_use] @@ -42,7 +45,8 @@ use rustc_query_system::query::QueryAccessors; pub use rustc_query_system::query::QueryConfig; pub(crate) use rustc_query_system::query::QueryDescription; -use rustc_middle::ty::query::on_disk_cache; +mod on_disk_cache; +pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs similarity index 95% rename from compiler/rustc_middle/src/ty/query/on_disk_cache.rs rename to compiler/rustc_query_impl/src/on_disk_cache.rs index 0ac80ebd6367b..b024668d63646 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,9 +1,4 @@ -use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use crate::mir::{self, interpret}; -use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; -use crate::ty::context::TyCtxt; -use crate::ty::{self, Ty}; +use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; @@ -12,6 +7,11 @@ use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use rustc_middle::mir::{self, interpret}; +use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; use rustc_query_system::query::QueryContext; use rustc_serialize::{ @@ -185,9 +185,8 @@ impl EncodedSourceFileId { } } -impl<'sess> OnDiskCache<'sess> { - /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { +impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { + fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -228,7 +227,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn new_empty(source_map: &'sess SourceMap) -> Self { + fn new_empty(source_map: &'sess SourceMap) -> Self { Self { serialized_data: Vec::new(), file_index_to_stable_id: Default::default(), @@ -249,11 +248,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn serialize<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - encoder: &mut FileEncoder, - ) -> FileEncodeResult { + fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -288,7 +283,7 @@ impl<'sess> OnDiskCache<'sess> { // Do this *before* we clone 'latest_foreign_def_path_hashes', since // loading existing queries may cause us to create new DepNodes, which // may in turn end up invoking `store_foreign_def_id_hash` - tcx.queries.exec_cache_promotions(tcx); + tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); @@ -311,7 +306,7 @@ impl<'sess> OnDiskCache<'sess> { tcx.sess.time("encode_query_results", || -> FileEncodeResult { let enc = &mut encoder; let qri = &mut query_result_index; - tcx.queries.encode_query_results(tcx, enc, qri) + QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri) })?; // Encode diagnostics. @@ -411,6 +406,88 @@ impl<'sess> OnDiskCache<'sess> { }) } + fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option { + let mut cache = self.def_path_hash_to_def_id_cache.lock(); + match cache.entry(hash) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + debug!("def_path_hash_to_def_id({:?})", hash); + // Check if the `DefPathHash` corresponds to a definition in the current + // crate + if let Some(def_id) = + tcx.definitions_untracked().local_def_path_hash_to_def_id(hash) + { + let def_id = def_id.to_def_id(); + e.insert(Some(def_id)); + return Some(def_id); + } + // This `raw_def_id` represents the `DefId` of this `DefPathHash` in + // the *previous* compliation session. The `DefPathHash` includes the + // owning crate, so if the corresponding definition still exists in the + // current compilation session, the crate is guaranteed to be the same + // (otherwise, we would compute a different `DefPathHash`). + let raw_def_id = self.get_raw_def_id(&hash)?; + debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); + // If the owning crate no longer exists, the corresponding definition definitely + // no longer exists. + let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; + debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); + // If our `DefPathHash` corresponded to a definition in the local crate, + // we should have either found it in `local_def_path_hash_to_def_id`, or + // never attempted to load it in the first place. Any query result or `DepNode` + // that references a local `DefId` should depend on some HIR-related `DepNode`. + // If a local definition is removed/modified such that its old `DefPathHash` + // no longer has a corresponding definition, that HIR-related `DepNode` should + // end up red. This should prevent us from ever calling + // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any + // queries involved. + debug_assert_ne!(krate, LOCAL_CRATE); + // Try to find a definition in the current session, using the previous `DefIndex` + // as an initial guess. + let opt_def_id = + tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash); + debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); + e.insert(opt_def_id); + opt_def_id + } + } + } + + fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } + } + } + } + + fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { + // We may overwrite an existing entry, but it will have the same value, + // so it's fine + self.latest_foreign_def_path_hashes + .lock() + .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); + } +} + +impl<'sess> OnDiskCache<'sess> { + pub fn as_dyn(&self) -> &dyn rustc_middle::ty::OnDiskCache<'sess> { + self as _ + } + /// Loads a diagnostic emitted during the previous compilation session. pub fn load_diagnostics( &self, @@ -449,44 +526,6 @@ impl<'sess> OnDiskCache<'sess> { cnum_map.get(&stable_crate_id).copied() } - pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { - // We may overwrite an existing entry, but it will have the same value, - // so it's fine - self.latest_foreign_def_path_hashes - .lock() - .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); - } - - /// If the given `dep_node`'s hash still exists in the current compilation, - /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. - /// - /// Normally, `store_foreign_def_id_hash` can be called directly by - /// the dependency graph when we construct a `DepNode`. However, - /// when we re-use a deserialized `DepNode` from the previous compilation - /// session, we only have the `DefPathHash` available. This method is used - /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written - /// out for usage in the next compilation session. - pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - // For reused dep nodes, we only need to store the mapping if the node - // is one whose query key we can reconstruct from the hash. We use the - // mapping to aid that reconstruction in the next session. While we also - // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, - // they're already registered during `DefId` encoding. - if dep_node.kind.can_reconstruct_query_key() { - let hash = DefPathHash(dep_node.hash.into()); - - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - if !def_id.is_local() { - self.store_foreign_def_id_hash(def_id, hash); - } - } - } - } - /// Returns the cached query result if there is something in the cache for /// the given `SerializedDepNodeIndex`; otherwise returns `None`. pub fn try_load_query_result<'tcx, T>( @@ -579,63 +618,6 @@ impl<'sess> OnDiskCache<'sess> { .collect() }) } - - /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation - /// session, if it still exists. This is used during incremental compilation to - /// turn a deserialized `DefPathHash` into its current `DefId`. - pub(crate) fn def_path_hash_to_def_id( - &self, - tcx: TyCtxt<'tcx>, - hash: DefPathHash, - ) -> Option { - let mut cache = self.def_path_hash_to_def_id_cache.lock(); - match cache.entry(hash) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - debug!("def_path_hash_to_def_id({:?})", hash); - // Check if the `DefPathHash` corresponds to a definition in the current - // crate - if let Some(def_id) = - tcx.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash) - { - let def_id = def_id.to_def_id(); - e.insert(Some(def_id)); - return Some(def_id); - } - // This `raw_def_id` represents the `DefId` of this `DefPathHash` in - // the *previous* compliation session. The `DefPathHash` includes the - // owning crate, so if the corresponding definition still exists in the - // current compilation session, the crate is guaranteed to be the same - // (otherwise, we would compute a different `DefPathHash`). - let raw_def_id = self.get_raw_def_id(&hash)?; - debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); - // If the owning crate no longer exists, the corresponding definition definitely - // no longer exists. - let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; - debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); - // If our `DefPathHash` corresponded to a definition in the local crate, - // we should have either found it in `local_def_path_hash_to_def_id`, or - // never attempted to load it in the first place. Any query result or `DepNode` - // that references a local `DefId` should depend on some HIR-related `DepNode`. - // If a local definition is removed/modified such that its old `DefPathHash` - // no longer has a corresponding definition, that HIR-related `DepNode` should - // end up red. This should prevent us from ever calling - // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any - // queries involved. - debug_assert_ne!(krate, LOCAL_CRATE); - // Try to find a definition in the current session, using the previous `DefIndex` - // as an initial guess. - let opt_def_id = tcx.untracked_resolutions.cstore.def_path_hash_to_def_id( - krate, - raw_def_id.index, - hash, - ); - debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); - e.insert(opt_def_id); - opt_def_id - } - } - } } //- DECODING ------------------------------------------------------------------- @@ -776,7 +758,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { } } -crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // This ensures that the `Decodable::decode` specialization for `Vec` is used // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt @@ -827,7 +809,7 @@ impl<'a, 'tcx> Decodable> for ExpnId { rustc_span::hygiene::register_local_expn_id(data, hash) } else { let index_guess = decoder.foreign_expn_data[&hash]; - decoder.tcx.untracked_resolutions.cstore.expn_hash_to_expn_id(krate, index_guess, hash) + decoder.tcx.cstore_untracked().expn_hash_to_expn_id(krate, index_guess, hash) }; #[cfg(debug_assertions)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5907a587e1690..6ed82ebfdb357 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,9 +2,8 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use super::queries; +use crate::{on_disk_cache, queries, Queries}; use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::ty::query::on_disk_cache; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; @@ -12,14 +11,16 @@ use rustc_query_system::query::{QueryContext, QueryDescription, QueryJobId, Quer use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::Diagnostic; +use rustc_errors::{Diagnostic, Handler}; use rustc_serialize::opaque; use rustc_span::def_id::LocalDefId; +use std::any::Any; + #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - pub queries: &'tcx super::Queries<'tcx>, + pub queries: &'tcx Queries<'tcx>, } impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { @@ -83,14 +84,15 @@ impl QueryContext for QueryCtxt<'tcx> { // Interactions with on_disk_cache fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { - self.on_disk_cache + self.queries + .on_disk_cache .as_ref() .map(|c| c.load_diagnostics(**self, prev_dep_node_index)) .unwrap_or_default() } fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics(dep_node_index, diagnostics) } } @@ -100,7 +102,7 @@ impl QueryContext for QueryCtxt<'tcx> { dep_node_index: DepNodeIndex, diagnostics: ThinVec, ) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics_for_anon_node(dep_node_index, diagnostics) } } @@ -137,6 +139,22 @@ impl QueryContext for QueryCtxt<'tcx> { } impl<'tcx> QueryCtxt<'tcx> { + #[inline] + pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self { + let queries = tcx.queries.as_any(); + let queries = unsafe { + let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries); + let queries = queries.downcast_ref().unwrap(); + let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries); + queries + }; + QueryCtxt { tcx, queries } + } + + crate fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> { + self.queries.on_disk_cache.as_ref() + } + pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, @@ -158,6 +176,15 @@ impl<'tcx> QueryCtxt<'tcx> { Ok(()) } + + pub fn try_print_query_stack( + self, + query: Option>, + handler: &Handler, + num_frames: Option, + ) -> usize { + rustc_query_system::query::print_query_stack(self, query, handler, num_frames) + } } /// This struct stores metadata about each Query. @@ -462,6 +489,8 @@ macro_rules! define_queries_struct { local_providers: Box, extern_providers: Box, + pub on_disk_cache: Option>, + $($(#[$attr])* $name: QueryState< crate::dep_graph::DepKind, query_keys::$name<$tcx>, @@ -472,10 +501,12 @@ macro_rules! define_queries_struct { pub fn new( local_providers: Providers, extern_providers: Providers, + on_disk_cache: Option>, ) -> Self { Queries { local_providers: Box::new(local_providers), extern_providers: Box::new(extern_providers), + on_disk_cache, $($name: Default::default()),* } } @@ -501,43 +532,22 @@ macro_rules! define_queries_struct { } impl QueryEngine<'tcx> for Queries<'tcx> { + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any { + let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) }; + this as _ + } + #[cfg(parallel_compiler)] unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { let tcx = QueryCtxt { tcx, queries: self }; rustc_query_system::query::deadlock(tcx, registry) } - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.encode_query_results(encoder, query_result_index) - } - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>) { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.dep_graph.exec_cache_promotions(tcx) - } - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { let qcx = QueryCtxt { tcx, queries: self }; tcx.dep_graph.try_mark_green(qcx, dep_node).is_some() } - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize { - let qcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::print_query_stack(qcx, query, handler, num_frames) - } - $($(#[$attr])* #[inline(always)] fn $name( From 5b921505ef0892e4d83d0e2743e3e2eecd03d461 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 28 Jun 2021 21:33:47 +0200 Subject: [PATCH 40/52] Remove deadlock virtual call. --- compiler/rustc_interface/src/util.rs | 4 +++- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/query.rs | 3 --- compiler/rustc_query_impl/src/plumbing.rs | 11 +++++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 4f51ce620427b..8b41a0ff17693 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,6 +10,8 @@ use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +#[cfg(parallel_compiler)] +use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; use rustc_session as session; use rustc_session::config::{self, CrateType}; @@ -176,7 +178,7 @@ unsafe fn handle_deadlock() { thread::spawn(move || { tls::enter_context(icx, |_| { rustc_span::set_session_globals_then(session_globals, || { - tls::with(|tcx| tcx.queries.deadlock(tcx, ®istry)) + tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(®istry)) }) }); }); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 47cc328f6c8bb..b84058011066f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -71,7 +71,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -pub trait OnDiskCache<'tcx> { +pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. fn new(sess: &'tcx Session, data: Vec, start_pos: usize) -> Self where diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 38ed82933fe94..15a8888ee65ed 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -233,9 +233,6 @@ macro_rules! define_callbacks { pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool; $($(#[$attr])* diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 6ed82ebfdb357..58c1b57dbb949 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -155,6 +155,11 @@ impl<'tcx> QueryCtxt<'tcx> { self.queries.on_disk_cache.as_ref() } + #[cfg(parallel_compiler)] + pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) { + rustc_query_system::query::deadlock(self, registry) + } + pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, @@ -537,12 +542,6 @@ macro_rules! define_queries_struct { this as _ } - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { - let tcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::deadlock(tcx, registry) - } - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { let qcx = QueryCtxt { tcx, queries: self }; tcx.dep_graph.try_mark_green(qcx, dep_node).is_some() From 0fcd59ad6548a93a9225aed0a42a24642ceeada0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jul 2021 12:43:39 +0200 Subject: [PATCH 41/52] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index b06130762ed75..250eff85c86b0 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit b06130762ed75f52da7c22979c61c597ced667c6 +Subproject commit 250eff85c86b089b77005691b899cea739f7e0cb From dbd4fd5716fb53086e35aa5d1548f5f709e439a0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Jul 2021 11:20:01 -0700 Subject: [PATCH 42/52] feat(rustc_lint): add `dyn_drop` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the conversation in #86747. Explanation ----------- A trait object bound of the form `dyn Drop` is most likely misleading and not what the programmer intended. `Drop` bounds do not actually indicate whether a type can be trivially dropped or not, because a composite type containing `Drop` types does not necessarily implement `Drop` itself. Naïvely, one might be tempted to write a deferred drop system, to pull cleaning up memory out of a latency-sensitive code path, using `dyn Drop` trait objects. However, this breaks down e.g. when `T` is `String`, which does not implement `Drop`, but should probably be accepted. To write a trait object bound that accepts anything, use a placeholder trait with a blanket implementation. ```rust trait Placeholder {} impl Placeholder for T {} fn foo(_x: Box) {} ``` --- compiler/rustc_lint/src/traits.rs | 63 +++++++++++++++++++++++++++- src/test/ui/dyn-drop/dyn-drop.rs | 16 +++++++ src/test/ui/dyn-drop/dyn-drop.stderr | 38 +++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/dyn-drop/dyn-drop.rs create mode 100644 src/test/ui/dyn-drop/dyn-drop.stderr diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index e632f29e672c0..e713ce7c71bec 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -37,10 +37,47 @@ declare_lint! { "bounds of the form `T: Drop` are useless" } +declare_lint! { + /// The `dyn_drop` lint checks for trait objects with `std::ops::Drop`. + /// + /// ### Example + /// + /// ```rust + /// fn foo(_x: Box) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trait object bound of the form `dyn Drop` is most likely misleading + /// and not what the programmer intended. + /// + /// `Drop` bounds do not actually indicate whether a type can be trivially + /// dropped or not, because a composite type containing `Drop` types does + /// not necessarily implement `Drop` itself. Naïvely, one might be tempted + /// to write a deferred drop system, to pull cleaning up memory out of a + /// latency-sensitive code path, using `dyn Drop` trait objects. However, + /// this breaks down e.g. when `T` is `String`, which does not implement + /// `Drop`, but should probably be accepted. + /// + /// To write a trait object bound that accepts anything, use a placeholder + /// trait with a blanket implementation. + /// + /// ```rust + /// trait Placeholder {} + /// impl Placeholder for T {} + /// fn foo(_x: Box) {} + /// ``` + pub DYN_DROP, + Warn, + "trait objects of the form `dyn Drop` are useless" +} + declare_lint_pass!( /// Lint for bounds of the form `T: Drop`, which usually /// indicate an attempt to emulate `std::mem::needs_drop`. - DropTraitConstraints => [DROP_BOUNDS] + DropTraitConstraints => [DROP_BOUNDS, DYN_DROP] ); impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { @@ -75,4 +112,28 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { } } } + + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { + let bounds = match &ty.kind { + hir::TyKind::TraitObject(bounds, _lifetime, _syntax) => bounds, + _ => return, + }; + for bound in &bounds[..] { + let def_id = bound.trait_ref.trait_def_id(); + if cx.tcx.lang_items().drop_trait() == def_id { + cx.struct_span_lint(DYN_DROP, bound.span, |lint| { + let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) { + Some(needs_drop) => needs_drop, + None => return, + }; + let msg = format!( + "types that do not implement `Drop` can still have drop glue, consider \ + instead using `{}` to detect whether a type is trivially dropped", + cx.tcx.def_path_str(needs_drop) + ); + lint.build(&msg).emit() + }); + } + } + } } diff --git a/src/test/ui/dyn-drop/dyn-drop.rs b/src/test/ui/dyn-drop/dyn-drop.rs new file mode 100644 index 0000000000000..e1668a3f188d5 --- /dev/null +++ b/src/test/ui/dyn-drop/dyn-drop.rs @@ -0,0 +1,16 @@ +#![deny(dyn_drop)] +#![allow(bare_trait_objects)] +fn foo(_: Box) {} //~ ERROR +fn bar(_: &dyn Drop) {} //~ERROR +fn baz(_: *mut Drop) {} //~ ERROR +struct Foo { + _x: Box //~ ERROR +} +trait Bar { + type T: ?Sized; +} +struct Baz {} +impl Bar for Baz { + type T = dyn Drop; //~ ERROR +} +fn main() {} diff --git a/src/test/ui/dyn-drop/dyn-drop.stderr b/src/test/ui/dyn-drop/dyn-drop.stderr new file mode 100644 index 0000000000000..1b1dbc4d12d4c --- /dev/null +++ b/src/test/ui/dyn-drop/dyn-drop.stderr @@ -0,0 +1,38 @@ +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:3:19 + | +LL | fn foo(_: Box) {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/dyn-drop.rs:1:9 + | +LL | #![deny(dyn_drop)] + | ^^^^^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:4:16 + | +LL | fn bar(_: &dyn Drop) {} + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:5:16 + | +LL | fn baz(_: *mut Drop) {} + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:7:15 + | +LL | _x: Box + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:14:16 + | +LL | type T = dyn Drop; + | ^^^^ + +error: aborting due to 5 previous errors + From 83d3a94b0474ceac3ea1a0d1e7e968e0de7f1033 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Jul 2021 11:52:19 -0700 Subject: [PATCH 43/52] Add `#![allow(dyn_drop)]` to test cases with `dyn Drop` in them These are all testing corner-cases in the compiler. Adding a new warning broke these test cases, but --cap-lints stops it from actually breaking things in production. --- .../dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs | 1 + src/test/ui/traits/object/issue-33140-traitobject-crate.rs | 1 + .../ui/traits/object/issue-33140-traitobject-crate.stderr | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs index 2b46f57c2e26f..59e7f9a6083ce 100644 --- a/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs +++ b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs @@ -10,6 +10,7 @@ // anything. #![deny(rust_2018_compatibility)] +#![allow(dyn_drop)] macro_rules! foo { () => { diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs index 46b68f1c9fe07..8abd92da362d3 100644 --- a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs @@ -1,6 +1,7 @@ // check-pass #![warn(order_dependent_trait_objects)] +#![allow(dyn_drop)] // Check that traitobject 0.1.0 compiles diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr index 781decb5ae281..77d71360b806b 100644 --- a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr @@ -1,5 +1,5 @@ warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:85:1 + --> $DIR/issue-33140-traitobject-crate.rs:86:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } | ------------------------------------------------------ first implementation here @@ -15,7 +15,7 @@ LL | #![warn(order_dependent_trait_objects)] = note: for more information, see issue #56484 warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:88:1 + --> $DIR/issue-33140-traitobject-crate.rs:89:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } | ------------------------------------------------------------- first implementation here @@ -27,7 +27,7 @@ LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } = note: for more information, see issue #56484 warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:92:1 + --> $DIR/issue-33140-traitobject-crate.rs:93:1 | LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } | ------------------------------------------------------ first implementation here From e054522b01c841b5b30f40ef25615af03fcd9b27 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 18 Jul 2021 07:57:03 -0700 Subject: [PATCH 44/52] fix(clippy): add missing allow(dyn_drop) --- src/tools/clippy/tests/ui/needless_lifetimes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index bda0801e51c7f..1d77382bf2cd1 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} From 3372f27cddfef8227882522c5bef92786bdab045 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 13 Mar 2021 16:05:15 +0100 Subject: [PATCH 45/52] require a `tcx` for `TypeVisitor` --- .../src/infer/error_reporting/mod.rs | 4 ++ .../nice_region_error/static_impl_trait.rs | 12 +++-- .../rustc_infer/src/infer/nll_relate/mod.rs | 6 +++ compiler/rustc_infer/src/infer/resolve.rs | 5 ++ compiler/rustc_lint/src/types.rs | 3 ++ compiler/rustc_middle/src/ty/fold.rs | 46 +++++++++++++++---- compiler/rustc_middle/src/ty/print/pretty.rs | 6 +++ compiler/rustc_mir/src/interpret/util.rs | 4 ++ .../src/monomorphize/polymorphize.rs | 14 ++++-- compiler/rustc_mir/src/util/pretty.rs | 4 ++ compiler/rustc_privacy/src/lib.rs | 4 ++ .../rustc_trait_selection/src/opaque_types.rs | 12 ++++- .../src/traits/object_safety.rs | 3 ++ .../src/traits/structural_match.rs | 3 ++ compiler/rustc_traits/src/chalk/lowering.rs | 14 +++++- compiler/rustc_ty_utils/src/instance.rs | 3 ++ compiler/rustc_typeck/src/check/check.rs | 17 +++++-- compiler/rustc_typeck/src/check/op.rs | 11 +++-- compiler/rustc_typeck/src/check/wfcheck.rs | 11 +++-- compiler/rustc_typeck/src/collect.rs | 2 +- .../src/constrained_generic_params.rs | 21 ++++++--- compiler/rustc_typeck/src/impl_wf_check.rs | 4 +- .../src/impl_wf_check/min_specialization.rs | 8 ++-- .../clippy_lints/src/redundant_clone.rs | 15 +++--- 24 files changed, 182 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e3a79fe265330..657bdd8cee3dc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1517,6 +1517,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { let span = self.tcx.def_span(def_id); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 1e926989263c9..b45a33df0a34a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -8,7 +8,9 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorRepor use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; -use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{ + self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, +}; use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; @@ -470,8 +472,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. struct TraitObjectVisitor(Vec); -impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { +impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for TraitObjectVisitor"); + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 20be06adfd09e..7732adba2a6d8 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -201,6 +201,7 @@ where }; value.skip_binder().visit_with(&mut ScopeInstantiator { + tcx: self.infcx.tcx, next_region: &mut next_region, target_index: ty::INNERMOST, bound_region_scope: &mut scope, @@ -756,6 +757,7 @@ where /// `for<..`>. For each of those, it creates an entry in /// `bound_region_scope`. struct ScopeInstantiator<'me, 'tcx> { + tcx: TyCtxt<'tcx>, next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, // The debruijn index of the scope we are instantiating. target_index: ty::DebruijnIndex, @@ -763,6 +765,10 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_binder>( &mut self, t: &ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 48b8ee17594e3..e5ad44c74271c 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -126,6 +126,11 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { type BreakTy = (Ty<'tcx>, Option); + + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a3a87a48768dc..fe5bafb41aac1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1160,6 +1160,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { type BreakTy = Ty<'tcx>; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.cx.tcx + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a40210d5a3622..40b3ffb895578 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -189,6 +189,12 @@ pub trait TypeFolder<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized { type BreakTy = !; + /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs + /// are not yet supplied. + /// + /// Visitors which do not look into these substs may leave this unimplemented, so be + /// careful when calling this method elsewhere. + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx>; fn visit_binder>( &mut self, @@ -301,7 +307,8 @@ impl<'tcx> TyCtxt<'tcx> { value: &impl TypeFoldable<'tcx>, callback: impl FnMut(ty::Region<'tcx>) -> bool, ) -> bool { - struct RegionVisitor { + struct RegionVisitor<'tcx, F> { + tcx: TyCtxt<'tcx>, /// The index of a binder *just outside* the things we have /// traversed. If we encounter a bound region bound by this /// binder or one outer to it, it appears free. Example: @@ -323,12 +330,16 @@ impl<'tcx> TyCtxt<'tcx> { callback: F, } - impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor + impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F> where F: FnMut(ty::Region<'tcx>) -> bool, { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -364,7 +375,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() + value + .visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback }) + .is_break() } } @@ -708,7 +721,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<'tcx>, { - let mut collector = LateBoundRegionsCollector::new(just_constraint); + let mut collector = LateBoundRegionsCollector::new(self, just_constraint); let result = value.as_ref().skip_binder().visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions @@ -775,6 +788,10 @@ impl<'tcx> ValidateBoundVars<'tcx> { impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("default anon const substs can't contain bound vars"); + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -989,6 +1006,10 @@ struct HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { type BreakTy = FoundEscapingVars; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for HasEscpaingVarsVisitor"); + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -1059,6 +1080,9 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for HasTypeFlagsVisitor"); + } #[inline] fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { @@ -1113,7 +1137,8 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { /// Collects all the late-bound regions at the innermost binding level /// into a hash set. -struct LateBoundRegionsCollector { +struct LateBoundRegionsCollector<'tcx> { + tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, regions: FxHashSet, @@ -1127,9 +1152,10 @@ struct LateBoundRegionsCollector { just_constrained: bool, } -impl LateBoundRegionsCollector { - fn new(just_constrained: bool) -> Self { +impl LateBoundRegionsCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self { LateBoundRegionsCollector { + tcx, current_index: ty::INNERMOST, regions: Default::default(), just_constrained, @@ -1137,7 +1163,11 @@ impl LateBoundRegionsCollector { } } -impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { +impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6dfbd28f7763b..ff8cbc10a701f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1949,6 +1949,7 @@ impl FmtPrinter<'_, 'tcx, F> { debug!("prepare_late_bound_region_info(value: {:?})", value); struct LateBoundRegionNameCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, used_region_names: &'a mut FxHashSet, type_collector: SsoHashSet>, } @@ -1956,6 +1957,10 @@ impl FmtPrinter<'_, 'tcx, F> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { @@ -1979,6 +1984,7 @@ impl FmtPrinter<'_, 'tcx, F> { self.used_region_names.clear(); let mut collector = LateBoundRegionNameCollector { + tcx: self.tcx, used_region_names: &mut self.used_region_names, type_collector: SsoHashSet::new(), }; diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index 89f34cd07aa4b..b7ab2e88b9623 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -21,6 +21,10 @@ where impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { type BreakTy = FoundParam; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if !c.needs_subst() { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 30e758c7fdf05..f2e1034f6a321 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -178,7 +178,7 @@ fn mark_used_by_predicates<'tcx>( // Consider all generic params in a predicate as used if any other parameter in the // predicate is used. let any_param_used = { - let mut vis = HasUsedGenericParams { unused_parameters }; + let mut vis = HasUsedGenericParams { tcx, unused_parameters }; predicate.visit_with(&mut vis).is_break() }; @@ -287,6 +287,9 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { if !c.has_param_types_or_consts() { @@ -350,13 +353,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } /// Visitor used to check if a generic parameter is used. -struct HasUsedGenericParams<'a> { +struct HasUsedGenericParams<'a, 'tcx> { + tcx: TyCtxt<'tcx>, unused_parameters: &'a FiniteBitSet, } -impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { +impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { if !c.has_param_types_or_consts() { diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index d0b1bc47ea800..8cc5a1874bf62 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -682,6 +682,10 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for CollectAllocIds") + } + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d969f50c1d918..14c518341d378 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -178,6 +178,10 @@ where { type BreakTy = V::BreakTy; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.def_id_visitor.tcx() + } + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index cc98cd7256628..dc1dd0dea43e4 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -424,6 +424,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { for required_region in required_region_bounds { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx, op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), }); } @@ -499,6 +500,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx, op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), }); } @@ -533,6 +535,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx: self.tcx, op: |r| { self.member_constraint( opaque_type_key.def_id, @@ -618,14 +621,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // // We ignore any type parameters because impl trait values are assumed to // capture all the in-scope type parameters. -struct ConstrainOpaqueTypeRegionVisitor { +struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> { + tcx: TyCtxt<'tcx>, op: OP, } -impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor +impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> where OP: FnMut(ty::Region<'tcx>), { + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_binder>( &mut self, t: &ty::Binder<'tcx, T>, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 7ebef7f8883ae..15f5b9b543414 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -769,6 +769,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 3d20a8d5cf336..a0c93cadbb6fe 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -131,6 +131,9 @@ impl Search<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { type BreakTy = NonStructuralMatchTy<'tcx>; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx() + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index a838172d664c3..466e6064d2b26 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -802,7 +802,7 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( tcx: TyCtxt<'tcx>, ty: Binder<'tcx, T>, ) -> (T, chalk_ir::VariableKinds>, BTreeMap) { - let mut bound_vars_collector = BoundVarsCollector::new(); + let mut bound_vars_collector = BoundVarsCollector::new(tcx); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); let mut parameters = bound_vars_collector.parameters; let named_parameters: BTreeMap = bound_vars_collector @@ -832,14 +832,16 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( } crate struct BoundVarsCollector<'tcx> { + tcx: TyCtxt<'tcx>, binder_index: ty::DebruijnIndex, crate parameters: BTreeMap>>, crate named_parameters: Vec, } impl<'tcx> BoundVarsCollector<'tcx> { - crate fn new() -> Self { + crate fn new(tcx: TyCtxt<'tcx>) -> Self { BoundVarsCollector { + tcx, binder_index: ty::INNERMOST, parameters: BTreeMap::new(), named_parameters: vec![], @@ -848,6 +850,10 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -1066,6 +1072,10 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for PlaceholdersCollector"); + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 469ac04e54515..a775bdb315ece 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -54,6 +54,9 @@ impl<'tcx> BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("default anon const substs can't be bound vars"); + } fn visit_binder>( &mut self, t: &Binder<'tcx, T>, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 496721e6f7634..570e4bedc332d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -531,14 +531,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( debug!(?item, ?span); struct FoundParentLifetime; - struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); + struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics); impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { type BreakTy = FoundParentLifetime; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.0 + } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("FindParentLifetimeVisitor: r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - if *index < self.0.parent_count as u32 { + if *index < self.1.parent_count as u32 { return ControlFlow::Break(FoundParentLifetime); } else { return ControlFlow::CONTINUE; @@ -560,21 +563,24 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } struct ProhibitOpaqueVisitor<'tcx> { + tcx: TyCtxt<'tcx>, opaque_identity_ty: Ty<'tcx>, generics: &'tcx ty::Generics, - tcx: TyCtxt<'tcx>, selftys: Vec<(Span, Option)>, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { type BreakTy = Ty<'tcx>; + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); if t == self.opaque_identity_ty { ControlFlow::CONTINUE } else { - t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) + t.super_visit_with(&mut FindParentLifetimeVisitor(self.tcx, self.generics)) .map_break(|FoundParentLifetime| t) } } @@ -1623,6 +1629,9 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { { struct VisitTypes(Vec); impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + bug!("tcx_for_anon_const_substs called for VisitTypes"); + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Opaque(def, _) => { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 963436d05d8ef..3503d68e8f029 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if let Some(missing_trait) = missing_trait { - let mut visitor = TypeParamVisitor(vec![]); + let mut visitor = TypeParamVisitor(self.tcx, vec![]); visitor.visit_ty(lhs_ty); if op.node == hir::BinOpKind::Add @@ -439,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted - } else if let [ty] = &visitor.0[..] { + } else if let [ty] = &visitor.1[..] { if let ty::Param(p) = *ty.kind() { // Check if the method would be found if the type param wasn't // involved. If so, it means that adding a trait bound to the param is @@ -1003,12 +1003,15 @@ fn suggest_constraining_param( } } -struct TypeParamVisitor<'tcx>(Vec>); +struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.0 + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if let ty::Param(_) = ty.kind() { - self.0.push(ty); + self.1.push(ty); } ty.super_visit_with(self) } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b24d63917c1cf..c6c925b092ea4 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -809,12 +809,15 @@ fn check_where_clauses<'tcx, 'fcx>( .predicates .iter() .flat_map(|&(pred, sp)| { - #[derive(Default)] - struct CountParams { + struct CountParams<'tcx> { + tcx: TyCtxt<'tcx>, params: FxHashSet, } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Param(param) = t.kind() { @@ -834,7 +837,7 @@ fn check_where_clauses<'tcx, 'fcx>( c.super_visit_with(self) } } - let mut param_count = CountParams::default(); + let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() }; let has_region = pred.visit_with(&mut param_count).is_break(); let substituted_pred = pred.subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 506ca98b96026..230bc39590a77 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2269,7 +2269,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP tcx, &mut predicates, trait_ref, - &mut cgp::parameters_for_impl(self_ty, trait_ref), + &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref), ); } diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 529de1a287484..140348ea4ec13 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -27,12 +27,13 @@ impl From for Parameter { /// Returns the set of parameters constrained by the impl header. pub fn parameters_for_impl<'tcx>( + tcx: TyCtxt<'tcx>, impl_self_ty: Ty<'tcx>, impl_trait_ref: Option>, ) -> FxHashSet { let vec = match impl_trait_ref { - Some(tr) => parameters_for(&tr, false), - None => parameters_for(&impl_self_ty, false), + Some(tr) => parameters_for(tcx, &tr, false), + None => parameters_for(tcx, &impl_self_ty, false), }; vec.into_iter().collect() } @@ -43,20 +44,26 @@ pub fn parameters_for_impl<'tcx>( /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. pub fn parameters_for<'tcx>( + tcx: TyCtxt<'tcx>, t: &impl TypeFoldable<'tcx>, include_nonconstraining: bool, ) -> Vec { - let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; + let mut collector = ParameterCollector { tcx, parameters: vec![], include_nonconstraining }; t.visit_with(&mut collector); collector.parameters } -struct ParameterCollector { +struct ParameterCollector<'tcx> { + tcx: TyCtxt<'tcx>, parameters: Vec, include_nonconstraining: bool, } -impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { +impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { @@ -198,12 +205,12 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(&projection.projection_ty, true); + let inputs = parameters_for(tcx, &projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for(&projection.ty, false)); + input_parameters.extend(parameters_for(tcx, &projection.ty, false)); } else { continue; } diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 1240946860573..194c4efdbb058 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -119,7 +119,7 @@ fn enforce_impl_params_are_constrained( let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref); + let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref); cgp::identify_constrained_generic_params( tcx, impl_predicates, @@ -136,7 +136,7 @@ fn enforce_impl_params_are_constrained( match item.kind { ty::AssocKind::Type => { if item.defaultness.has_value() { - cgp::parameters_for(&tcx.type_of(def_id), true) + cgp::parameters_for(tcx, &tcx.type_of(def_id), true) } else { Vec::new() } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 505d9a59d9c2f..1f3996c0646cc 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -207,15 +207,15 @@ fn unconstrained_parent_impl_substs<'tcx>( continue; } - unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true)); - for param in cgp::parameters_for(&projected_ty, false) { + for param in cgp::parameters_for(tcx, &projected_ty, false) { if !unconstrained_parameters.contains(¶m) { constrained_params.insert(param.0); } } - unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true)); } } @@ -249,7 +249,7 @@ fn check_duplicate_params<'tcx>( parent_substs: &Vec>, span: Span, ) { - let mut base_params = cgp::parameters_for(parent_substs, true); + let mut base_params = cgp::parameters_for(tcx, parent_substs, true); base_params.sort_by_key(|param| param.0); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_substs[duplicate.0 as usize]; diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 7ba7ff3a353f9..ceaee314b469e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::{ visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, Mutability, }; -use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; +use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt}; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; @@ -575,7 +575,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { self.possible_borrower.add(borrowed.local, lhs); }, other => { - if ContainsRegion + if ContainsRegion(self.cx.tcx) .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) .is_continue() { @@ -624,7 +624,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { .flat_map(HybridBitSet::iter) .collect(); - if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() { + if ContainsRegion(self.cx.tcx).visit_ty(self.body.local_decls[*dest].ty).is_break() { mutable_variables.push(*dest); } @@ -700,12 +700,15 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> { } } -struct ContainsRegion; +struct ContainsRegion<'tcx>(TyCtxt<'tcx>); -impl TypeVisitor<'_> for ContainsRegion { +impl<'tcx> TypeVisitor<'tcx> for ContainsRegion<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { + self.0 + } - fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { ControlFlow::BREAK } } From 1bc1691ef5134397ce8002fd5e490c32070e5feb Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 16 Mar 2021 00:05:45 +0100 Subject: [PATCH 46/52] make unevaluated const substs optional --- .../rustc_codegen_cranelift/src/constant.rs | 10 ++--- compiler/rustc_infer/src/infer/combine.rs | 18 ++++----- .../src/infer/error_reporting/mod.rs | 4 +- .../nice_region_error/static_impl_trait.rs | 6 ++- compiler/rustc_infer/src/infer/mod.rs | 8 ++-- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +- compiler/rustc_infer/src/infer/resolve.rs | 4 +- compiler/rustc_lint/src/types.rs | 4 +- .../rustc_middle/src/mir/interpret/queries.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 ++ compiler/rustc_middle/src/ty/consts.rs | 3 +- compiler/rustc_middle/src/ty/consts/kind.rs | 38 +++++++++++++------ compiler/rustc_middle/src/ty/flags.rs | 3 +- compiler/rustc_middle/src/ty/fold.rs | 35 ++++++++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 23 +++++------ compiler/rustc_middle/src/ty/relate.rs | 8 ++-- .../rustc_middle/src/ty/structural_impls.rs | 31 +++++++++++---- compiler/rustc_middle/src/ty/walk.rs | 3 +- .../src/borrow_check/type_check/mod.rs | 8 ++-- compiler/rustc_mir/src/interpret/operand.rs | 6 +-- compiler/rustc_mir/src/interpret/util.rs | 4 +- .../src/monomorphize/polymorphize.rs | 16 ++++---- .../src/transform/check_consts/qualifs.rs | 2 +- .../rustc_mir/src/transform/const_prop.rs | 2 +- .../rustc_mir/src/transform/promote_consts.rs | 18 +++++---- compiler/rustc_mir/src/util/pretty.rs | 8 ++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 14 +++---- compiler/rustc_privacy/src/lib.rs | 4 +- .../rustc_trait_selection/src/opaque_types.rs | 4 +- .../src/traits/const_evaluatable.rs | 11 ++---- .../src/traits/fulfill.rs | 14 +++---- .../src/traits/object_safety.rs | 4 +- .../src/traits/select/mod.rs | 8 ++-- .../src/traits/structural_match.rs | 4 +- .../rustc_trait_selection/src/traits/wf.rs | 9 +++-- compiler/rustc_traits/src/chalk/lowering.rs | 9 +++-- compiler/rustc_ty_utils/src/instance.rs | 5 ++- compiler/rustc_typeck/src/check/check.rs | 19 +++++----- compiler/rustc_typeck/src/check/op.rs | 4 +- compiler/rustc_typeck/src/check/wfcheck.rs | 4 +- compiler/rustc_typeck/src/collect.rs | 4 +- compiler/rustc_typeck/src/collect/type_of.rs | 6 ++- .../src/constrained_generic_params.rs | 4 +- src/librustdoc/clean/utils.rs | 2 +- .../clippy/clippy_lints/src/non_copy_const.rs | 6 +-- .../clippy_lints/src/redundant_clone.rs | 4 +- src/tools/clippy/clippy_utils/src/consts.rs | 6 +-- 47 files changed, 232 insertions(+), 185 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c87309e22224f..424a0d742d12b 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -129,13 +129,13 @@ pub(crate) fn codegen_constant<'tcx>( }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, - ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if fx.tcx.is_static(def.did) => + ConstKind::Unevaluated(uv) + if fx.tcx.is_static(uv.def.did) => { - assert!(substs.is_empty()); - assert!(promoted.is_none()); + assert!(uv.substs(fx.tcx).is_empty()); + assert!(uv.promoted.is_none()); - return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); + return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx); } ConstKind::Unevaluated(unevaluated) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 3a11b5a214490..6065bb02d681d 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -737,10 +737,9 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { + assert_eq!(uv.promoted, None); + let substs = uv.substs(self.tcx()); let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -749,7 +748,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, - val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)), })) } _ => relate::super_relate_consts(self, c, c), @@ -971,10 +970,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { + assert_eq!(uv.promoted, None); + let substs = uv.substs(self.tcx()); let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -983,7 +981,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, - val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)), })) } _ => relate::super_relate_consts(self, c, c), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 657bdd8cee3dc..de78f49007f3f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1517,8 +1517,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b45a33df0a34a..0f02b841d23e3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -473,8 +473,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct TraitObjectVisitor(Vec); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for TraitObjectVisitor"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // The default anon const substs cannot include + // trait objects, so we don't have to bother looking. + None } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f39431f2494b1..b1522dc7da4b3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1487,16 +1487,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, - ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx>, span: Option, ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); - let canonical = self.canonicalize_query((param_env, substs), &mut original_values); + let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values); - let (param_env, substs) = canonical.value; + let (param_env, unevaluated) = canonical.value; // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. - self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span) + self.tcx.const_eval_resolve(param_env, unevaluated, span) } /// If `typ` is a type variable of some kind, resolve it one level diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 7732adba2a6d8..9417731872ce0 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -765,8 +765,8 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_binder>( diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index e5ad44c74271c..4b08c2eb9c19e 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -127,8 +127,8 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { type BreakTy = (Ty<'tcx>, Option); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.infcx.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.infcx.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fe5bafb41aac1..794e6cb0ba3e1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1160,8 +1160,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { type BreakTy = Ty<'tcx>; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.cx.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.cx.tcx) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fa7c0670e8ce6..c63613ae3af29 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { ct: ty::Unevaluated<'tcx>, span: Option, ) -> EvalToConstValueResult<'tcx> { - match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: ct.promoted }; self.const_eval_global_id(param_env, cid, span) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cb99ae19ee72e..33eef0bd4f197 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -114,6 +114,10 @@ rustc_queries! { desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } } + query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> { + desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) } + } + /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index c78151271c171..869b2ab9dbcbc 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,6 +1,5 @@ use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::subst::InternalSubsts; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{ParamEnv, ParamEnvAnd}; use rustc_errors::ErrorReported; @@ -100,7 +99,7 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs_: None, promoted: None, }), }; diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index f2db95d162b88..ab2c57ac605b7 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -16,10 +16,23 @@ use super::ScalarInt; #[derive(Hash, HashStable)] pub struct Unevaluated<'tcx> { pub def: ty::WithOptConstParam, - pub substs: SubstsRef<'tcx>, + pub substs_: Option>, pub promoted: Option, } +impl<'tcx> Unevaluated<'tcx> { + pub fn new(def: ty::WithOptConstParam, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx> { + Unevaluated { def, substs_: Some(substs), promoted: None } + } + + pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> { + self.substs_.unwrap_or_else(|| { + debug_assert_eq!(self.promoted, None); + tcx.default_anon_const_substs(self.def.did) + }) + } +} + /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] @@ -109,7 +122,7 @@ impl<'tcx> ConstKind<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option, ErrorReported>> { - if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self { + if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` @@ -118,29 +131,32 @@ impl<'tcx> ConstKind<'tcx> { // Note that we erase regions *before* calling `with_reveal_all_normalized`, // so that we don't try to invoke this query with // any region variables. - let param_env_and_substs = tcx + let param_env_and = tcx .erase_regions(param_env) .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(substs)); + .and(tcx.erase_regions(unevaluated)); // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed // when the expression doesn't depend on any parameters. // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // we can call `infcx.const_eval_resolve` which handles inference variables. - let param_env_and_substs = if param_env_and_substs.needs_infer() { - tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did)) + let param_env_and = if param_env_and.needs_infer() { + tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { + def: unevaluated.def, + substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)), + promoted: unevaluated.promoted, + }) } else { - param_env_and_substs + param_env_and }; // FIXME(eddyb) maybe the `const_eval_*` methods should take - // `ty::ParamEnvAnd` instead of having them separate. - let (param_env, substs) = param_env_and_substs.into_parts(); + // `ty::ParamEnvAnd` instead of having them separate. + let (param_env, unevaluated) = param_env_and.into_parts(); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None) - { + match tcx.const_eval_resolve(param_env, unevaluated, None) { // NOTE(eddyb) `val` contains no lifetimes/types/consts, // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 9faa172a4973f..e1985ea74ae79 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -301,7 +301,8 @@ impl FlagComputation { } fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) { - self.add_substs(ct.substs); + // TODO + self.add_substs(ct.substs_.unwrap()); self.add_flags(TypeFlags::HAS_CT_PROJECTION); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 40b3ffb895578..6e70e8ddaed80 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -192,9 +192,11 @@ pub trait TypeVisitor<'tcx>: Sized { /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs /// are not yet supplied. /// - /// Visitors which do not look into these substs may leave this unimplemented, so be - /// careful when calling this method elsewhere. - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx>; + /// Visitors which do not look into these substs may return `None` here, in which case + /// `super_visit_with` completely skips the default substs. Incorrectly returning + /// `None` can very quickly lead to ICE or other critical bugs, so be careful and + /// try to return an actual `tcx` if at all possible. + fn tcx_for_anon_const_substs(&self) -> Option>; fn visit_binder>( &mut self, @@ -336,8 +338,8 @@ impl<'tcx> TyCtxt<'tcx> { { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_binder>( @@ -788,8 +790,9 @@ impl<'tcx> ValidateBoundVars<'tcx> { impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("default anon const substs can't contain bound vars"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anonymous constants do not contain bound vars in their substs by default. + None } fn visit_binder>( @@ -1006,8 +1009,9 @@ struct HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { type BreakTy = FoundEscapingVars; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for HasEscpaingVarsVisitor"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anonymous constants do not contain bound vars in their substs by default. + None } fn visit_binder>( @@ -1080,8 +1084,13 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for HasTypeFlagsVisitor"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // TypeFlagsVisitor must not look into the default anon const substs + // as that would cause cycle errors, but we do care about them for + // some flags. + // + // We therefore have to be very careful here. + None } #[inline] @@ -1164,8 +1173,8 @@ impl LateBoundRegionsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_binder>( diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ff8cbc10a701f..820d858e3c5a1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -927,20 +927,21 @@ pub trait PrettyPrinter<'tcx>: } match ct.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - if let Some(promoted) = promoted { - p!(print_value_path(def.did, substs)); + ty::ConstKind::Unevaluated(uv) => { + if let Some(promoted) = uv.promoted { + let substs = uv.substs_.unwrap(); + p!(print_value_path(uv.def.did, substs)); p!(write("::{:?}", promoted)); } else { - match self.tcx().def_kind(def.did) { + let tcx = self.tcx(); + match tcx.def_kind(uv.def.did) { DefKind::Static | DefKind::Const | DefKind::AssocConst => { - p!(print_value_path(def.did, substs)) + p!(print_value_path(uv.def.did, uv.substs(tcx))) } _ => { - if def.is_local() { - let span = self.tcx().def_span(def.did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) - { + if uv.def.is_local() { + let span = tcx.def_span(uv.def.did); + if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) { p!(write("{}", snip)) } else { print_underscore!() @@ -1957,8 +1958,8 @@ impl FmtPrinter<'_, 'tcx, F> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index a4c36be21992b..3514027cc82f9 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -552,7 +552,7 @@ pub fn super_relate_consts>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().const_evaluatable_checked => { - tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs))) + tcx.try_unify_abstract_consts(((au.def, au.substs(tcx)), (bu.def, bu.substs(tcx)))) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` @@ -564,13 +564,13 @@ pub fn super_relate_consts>( let substs = relation.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), - au.substs, - bu.substs, + au.substs(tcx), + bu.substs(tcx), )?; return Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: au.def, - substs, + substs_: Some(substs), promoted: au.promoted, }), ty: a.ty, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7290c41d615df..81ac5825473ee 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1039,13 +1039,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match self { ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs: substs.fold_with(folder), - promoted, - }) - } + ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) @@ -1057,7 +1051,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor), + ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) @@ -1075,3 +1069,24 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { ControlFlow::CONTINUE } } + +impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::Unevaluated { + def: self.def, + substs_: Some(self.substs(folder.tcx()).fold_with(folder)), + promoted: self.promoted, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { + if let Some(tcx) = visitor.tcx_for_anon_const_substs() { + self.substs(tcx).visit_with(visitor) + } else if let Some(substs) = self.substs_ { + substs.visit_with(visitor) + } else { + debug!("ignoring default substs of `{:?}`", self.def); + ControlFlow::CONTINUE + } + } +} diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index c2fe5f1ef3f62..c9fc97f0aaf98 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -196,7 +196,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Error(_) => {} ty::ConstKind::Unevaluated(ct) => { - stack.extend(ct.substs.iter().rev()); + // TODO + stack.extend(ct.substs_.unwrap().iter().rev()); } } } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index b4fe3313e8a1e..a4ed0660dc0bd 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -322,8 +322,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { }, _ => None, }; - if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval { - if let Some(promoted) = promoted { + if let Some(uv) = maybe_uneval { + if let Some(promoted) = uv.promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, promoted: &Body<'tcx>, ty, @@ -358,8 +358,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( constant.literal.ty(), - def.did, - UserSubsts { substs, user_self_ty: None }, + uv.def.did, + UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, )), ) { span_mirbug!( diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index aba7db7816843..c90af5d7663fd 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -541,9 +541,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match val.val { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - let instance = self.resolve(def, substs)?; - Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()) + ty::ConstKind::Unevaluated(uv) => { + let instance = self.resolve(uv.def, uv.substs(*self.tcx))?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) } ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index b7ab2e88b9623..b9d6e002e2db1 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -21,8 +21,8 @@ where impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { type BreakTy = FoundParam; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index f2e1034f6a321..204b3b135228f 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -287,8 +287,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { @@ -302,7 +302,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.unused_parameters.clear(param.index); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)}) + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)}) // Avoid considering `T` unused when constants are of the form: // `>::foo::promoted[p]` if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => @@ -313,10 +313,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.visit_body(&promoted[p]); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) - if self.tcx.def_kind(def.did) == DefKind::AnonConst => + ty::ConstKind::Unevaluated(uv) + if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => { - self.visit_child_body(def.did, substs); + self.visit_child_body(uv.def.did, uv.substs(self.tcx)); ControlFlow::CONTINUE } _ => c.super_visit_with(self), @@ -361,8 +361,8 @@ struct HasUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } #[instrument(skip(self))] diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index ac8c748ea8571..413a9638eb37b 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -247,7 +247,7 @@ where // Check the qualifs of the value of `const` items. if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val { + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { assert!(promoted.is_none()); // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def.did).is_none() { diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index e02e41d62061a..8d819bf44ec79 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -483,7 +483,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Promoteds must lint and not error as the user didn't ask for them ConstKind::Unevaluated(ty::Unevaluated { def: _, - substs: _, + substs_: _, promoted: Some(_), }) => true, // Out of backwards compatibility we cannot report hard errors in unused diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 78e84419c62cd..428778a6718e2 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -859,13 +859,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { ty, val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, - substs: InternalSubsts::for_item(tcx, def.did, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), + substs_: Some(InternalSubsts::for_item( + tcx, + def.did, + |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }, + )), promoted: Some(promoted_id), }), }) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 8cc5a1874bf62..e1399fa6a1b07 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -475,7 +475,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Unevaluated(uv) => format!( "Unevaluated({}, {:?}, {:?})", self.tcx.def_path_str(uv.def.did), - uv.substs, + uv.substs(self.tcx), uv.promoted ), ty::ConstKind::Value(val) => format!("Value({:?})", val), @@ -682,8 +682,10 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for CollectAllocIds") + fn tcx_for_anon_const_substs(&self) -> Option> { + // `AllocId`s are only inside of `ConstKind::Value` which + // can't be part of the anon const default substs. + None } fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index c3908ddd4fbe8..75e356433cce4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -690,11 +690,10 @@ impl<'tcx> Cx<'tcx> { // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(self.tcx(), did); let lhs = ty::Const { - val: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(did), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( + ty::WithOptConstParam::unknown(did), substs, - promoted: None, - }), + )), ty: var_ty, }; let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs))); @@ -886,11 +885,10 @@ impl<'tcx> Cx<'tcx> { debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { literal: self.tcx.mk_const(ty::Const { - val: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( + ty::WithOptConstParam::unknown(def_id), substs, - promoted: None, - }), + )), ty: self.typeck_results().node_type(expr.hir_id), }), user_ty, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 14c518341d378..9d44c0c873554 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -178,8 +178,8 @@ where { type BreakTy = V::BreakTy; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.def_id_visitor.tcx() + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.def_id_visitor.tcx()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index dc1dd0dea43e4..71b18b55cfa0d 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -630,8 +630,8 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> where OP: FnMut(ty::Region<'tcx>), { - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_binder>( diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b1a938836b70e..2f1e7e9d509b4 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -155,11 +155,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // and hopefully soon change this to an error. // // See #74595 for more details about this. - let concrete = infcx.const_eval_resolve( - param_env, - ty::Unevaluated { def, substs, promoted: None }, - Some(span), - ); + let concrete = + infcx.const_eval_resolve(param_env, ty::Unevaluated::new(def, substs), Some(span)); if concrete.is_ok() && substs.has_param_types_or_consts() { match infcx.tcx.def_kind(def.did) { @@ -217,9 +214,7 @@ impl AbstractConst<'tcx> { ct: &ty::Const<'tcx>, ) -> Result>, ErrorReported> { match ct.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => { - AbstractConst::new(tcx, def, substs) - } + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.def, uv.substs(tcx)), ty::ConstKind::Error(_) => Err(ErrorReported), _ => Ok(None), } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index dfe2909498d18..7ac3ae34637fd 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -516,7 +516,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { debug!(?c1, ?c2, "equating consts"); - if self.selcx.tcx().features().const_evaluatable_checked { + let tcx = self.selcx.tcx(); + if tcx.features().const_evaluatable_checked { // FIXME: we probably should only try to unify abstract constants // if the constants depend on generic parameters. // @@ -524,11 +525,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if self - .selcx - .tcx() - .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs))) - { + if tcx.try_unify_abstract_consts(( + (a.def, a.substs(tcx)), + (b.def, b.substs(tcx)), + )) { return ProcessResult::Changed(vec![]); } } @@ -547,7 +547,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { Err(ErrorHandled::TooGeneric) => { stalled_on.extend( unevaluated - .substs + .substs(tcx) .iter() .filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 15f5b9b543414..113ca8b407ea6 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -769,8 +769,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 564c63ef30cb6..1a4fe14e689a2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -573,10 +573,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if self - .tcx() - .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs))) - { + if self.tcx().try_unify_abstract_consts(( + (a.def, a.substs(self.tcx())), + (b.def, b.substs(self.tcx())), + )) { return Ok(EvaluatedToOk); } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index a0c93cadbb6fe..0f1d0117ea09c 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -131,8 +131,8 @@ impl Search<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { type BreakTy = NonStructuralMatchTy<'tcx>; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx() + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 27c8e00c5596c..b7853e0bc6f64 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -431,13 +431,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { GenericArgKind::Const(constant) => { match constant.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - assert!(promoted.is_none()); + ty::ConstKind::Unevaluated(uv) => { + assert!(uv.promoted.is_none()); + let substs = uv.substs(self.tcx()); - let obligations = self.nominal_obligations(def.did, substs); + let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def, substs) + let predicate = ty::PredicateKind::ConstEvaluatable(uv.def, substs) .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 466e6064d2b26..7efd7d34b807d 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -850,8 +850,8 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_binder>( @@ -1072,8 +1072,9 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for PlaceholdersCollector"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anon const substs do not contain placeholders by default. + None } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index a775bdb315ece..c1713814e8305 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -54,8 +54,9 @@ impl<'tcx> BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("default anon const substs can't be bound vars"); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anon const substs do not contain bound vars by default. + None } fn visit_binder>( &mut self, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 570e4bedc332d..723366be89555 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -534,8 +534,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics); impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { type BreakTy = FoundParentLifetime; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.0 + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { @@ -571,8 +571,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { type BreakTy = Ty<'tcx>; - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { @@ -1627,10 +1627,11 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) { - struct VisitTypes(Vec); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - bug!("tcx_for_anon_const_substs called for VisitTypes"); + struct OpaqueTypeCollector(Vec); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector { + fn tcx_for_anon_const_substs(&self) -> Option> { + // Default anon const substs cannot contain opaque types. + None } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { @@ -1642,7 +1643,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { } } } - let mut visitor = VisitTypes(vec![]); + let mut visitor = OpaqueTypeCollector(vec![]); ty.visit_with(&mut visitor); for def_id in visitor.0 { let ty_span = tcx.def_span(def_id); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 3503d68e8f029..9b495fba1975d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -1006,8 +1006,8 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.0 + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if let ty::Param(_) = ty.kind() { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index c6c925b092ea4..9d783991c6d38 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -815,8 +815,8 @@ fn check_where_clauses<'tcx, 'fcx>( } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 230bc39590a77..46c610636e31f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -71,6 +71,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub fn provide(providers: &mut Providers) { *providers = Providers { opt_const_param_of: type_of::opt_const_param_of, + default_anon_const_substs: type_of::default_anon_const_substs, type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, @@ -2304,7 +2305,8 @@ fn const_evaluatable_predicates_of<'tcx>( assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs).to_predicate(self.tcx), + ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs(self.tcx)) + .to_predicate(self.tcx), span, )); } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7b0002914eca8..8459a3b248ee0 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -7,7 +7,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; @@ -268,6 +268,10 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } +pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { + InternalSubsts::identity_for_item(tcx, def_id) +} + pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let def_id = def_id.expect_local(); use rustc_hir::*; diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 140348ea4ec13..9b6f0be47caf5 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -60,8 +60,8 @@ struct ParameterCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> { - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.tcx + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bdd5350aab2cb..bdfe3ffc13f13 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -287,7 +287,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { match n.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => { let mut s = if let Some(def) = def.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id)) diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index d775cd7c7f740..38ce7be1a113a 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -181,11 +181,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D let result = cx.tcx.const_eval_resolve( cx.param_env, - ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), - substs, - promoted: None, - }, + ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ); is_value_unfrozen_raw(cx, result, ty) diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index ceaee314b469e..a1be0bcca872e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -704,8 +704,8 @@ struct ContainsRegion<'tcx>(TyCtxt<'tcx>); impl<'tcx> TypeVisitor<'tcx> for ContainsRegion<'tcx> { type BreakTy = (); - fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> { - self.0 + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) } fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 15c27d1a996d7..a2639abcb8078 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -346,11 +346,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve( self.param_env, - ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), - substs, - promoted: None, - }, + ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ) .ok() From 2e13be1441dc0e1f990bca640adfac3f9bdf1e8f Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Jul 2021 16:43:23 +0200 Subject: [PATCH 47/52] add `tcx` to `fn walk` --- .../infer/error_reporting/need_type_info.rs | 2 +- .../rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_middle/src/ty/outlives.rs | 2 +- compiler/rustc_middle/src/ty/walk.rs | 41 +++++++++++-------- .../rustc_mir/src/monomorphize/collector.rs | 2 +- .../src/transform/check_consts/validation.rs | 2 +- .../src/transform/function_item_references.rs | 4 +- .../src/thir/pattern/const_to_pat.rs | 2 +- .../src/traits/fulfill.rs | 5 ++- .../src/traits/object_safety.rs | 2 +- .../src/traits/select/confirmation.rs | 8 ++-- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 4 +- compiler/rustc_typeck/src/astconv/mod.rs | 4 +- compiler/rustc_typeck/src/check/check.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 2 +- .../src/outlives/implicit_infer.rs | 4 +- src/tools/clippy/clippy_lints/src/escape.rs | 4 +- .../clippy/clippy_lints/src/let_underscore.rs | 2 +- .../clippy_lints/src/loops/same_item_push.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 10 ++--- src/tools/clippy/clippy_lints/src/returns.rs | 2 +- .../clippy_lints/src/unnecessary_sort_by.rs | 2 +- src/tools/clippy/clippy_lints/src/use_self.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/tools/clippy/clippy_utils/src/ty.rs | 12 +++--- 28 files changed, 71 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index d9a1193aac4ba..389b6700f2ec3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { fn node_ty_contains_target(&self, hir_id: HirId) -> Option> { self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| { - ty.walk().any(|inner| { + ty.walk(self.infcx.tcx).any(|inner| { inner == self.target || match (inner.unpack(), self.target.unpack()) { (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index f69212c599b62..dba73251b4f0d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -189,7 +189,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { let mut bounds = parent - .walk_shallow(visited) + .walk_shallow(self.tcx, visited) .filter_map(|child| match child.unpack() { GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Lifetime(lt) => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ccdbccae156c3..261f95979083f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -155,8 +155,8 @@ declare_lint! { declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { - fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { - for leaf in ty.walk() { + fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { + for leaf in ty.walk(cx.tcx) { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if leaf_ty.is_box() { cx.struct_span_lint(BOX_POINTERS, span, |lint| { diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 86750d5c08111..ef4ad998f10c8 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -194,7 +194,7 @@ fn compute_components_recursive( out: &mut SmallVec<[Component<'tcx>; 4]>, visited: &mut SsoHashSet>, ) { - for child in parent.walk_shallow(visited) { + for child in parent.walk_shallow(tcx, visited) { match child.unpack() { GenericArgKind::Type(ty) => { compute_components(tcx, ty, out, visited); diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index c9fc97f0aaf98..3cab813f12ad0 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -1,8 +1,8 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; +use crate::ty::{self, TyCtxt}; use rustc_data_structures::sso::SsoHashSet; use smallvec::{self, SmallVec}; @@ -11,6 +11,7 @@ use smallvec::{self, SmallVec}; type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { + tcx: TyCtxt<'tcx>, stack: TypeWalkerStack<'tcx>, last_subtree: usize, pub visited: SsoHashSet>, @@ -25,8 +26,8 @@ pub struct TypeWalker<'tcx> { /// It maintains a set of visited types and /// skips any types that are already there. impl<'tcx> TypeWalker<'tcx> { - pub fn new(root: GenericArg<'tcx>) -> Self { - Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } + fn new(tcx: TyCtxt<'tcx>, root: GenericArg<'tcx>) -> Self { + Self { tcx, stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } } /// Skips the subtree corresponding to the last type @@ -55,7 +56,7 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { let next = self.stack.pop()?; self.last_subtree = self.stack.len(); if self.visited.insert(next) { - push_inner(&mut self.stack, next); + push_inner(self.tcx, &mut self.stack, next); debug!("next: stack={:?}", self.stack); return Some(next); } @@ -74,8 +75,8 @@ impl GenericArg<'tcx> { /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self) + pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { + TypeWalker::new(tcx, self) } /// Iterator that walks the immediate children of `self`. Hence @@ -87,10 +88,11 @@ impl GenericArg<'tcx> { /// and skips any types that are already there. pub fn walk_shallow( self, + tcx: TyCtxt<'tcx>, visited: &mut SsoHashSet>, ) -> impl Iterator> { let mut stack = SmallVec::new(); - push_inner(&mut stack, self); + push_inner(tcx, &mut stack, self); stack.retain(|a| visited.insert(*a)); stack.into_iter() } @@ -107,18 +109,22 @@ impl<'tcx> super::TyS<'tcx> { /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) + pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { + TypeWalker::new(tcx, self.into()) } } -// We push `GenericArg`s on the stack in reverse order so as to -// maintain a pre-order traversal. As of the time of this -// writing, the fact that the traversal is pre-order is not -// known to be significant to any code, but it seems like the -// natural order one would expect (basically, the order of the -// types as they are written). -fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { +/// We push `GenericArg`s on the stack in reverse order so as to +/// maintain a pre-order traversal. As of the time of this +/// writing, the fact that the traversal is pre-order is not +/// known to be significant to any code, but it seems like the +/// natural order one would expect (basically, the order of the +/// types as they are written). +fn push_inner<'tcx>( + tcx: TyCtxt<'tcx>, + stack: &mut TypeWalkerStack<'tcx>, + parent: GenericArg<'tcx>, +) { match parent.unpack() { GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { ty::Bool @@ -196,8 +202,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Error(_) => {} ty::ConstKind::Unevaluated(ct) => { - // TODO - stack.extend(ct.substs_.unwrap().iter().rev()); + stack.extend(ct.substs(tcx).iter().rev()); } } } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 2ce7cf71116bb..d7c4fbc373730 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -573,7 +573,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { let type_length = instance .substs .iter() - .flat_map(|arg| arg.walk()) + .flat_map(|arg| arg.walk(tcx)) .filter(|arg| match arg.unpack() { GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Lifetime(_) => false, diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 646ae8ced7eb4..79b78c2cb05c5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -365,7 +365,7 @@ impl Validator<'mir, 'tcx> { fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { let kind = self.body.local_kind(local); - for ty in ty.walk() { + for ty in ty.walk(self.tcx) { let ty = match ty.unpack() { GenericArgKind::Type(ty) => ty, diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs index 8d02ac6d9b774..7ffb5950fdc9e 100644 --- a/compiler/rustc_mir/src/transform/function_item_references.rs +++ b/compiler/rustc_mir/src/transform/function_item_references.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { // Handle calls to `transmute` if self.tcx.is_diagnostic_item(sym::transmute, def_id) { let arg_ty = args[0].ty(self.body, self.tcx); - for generic_inner_ty in arg_ty.walk() { + for generic_inner_ty in arg_ty.walk(self.tcx) { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(inner_ty) @@ -110,7 +110,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); for (arg_num, arg_def) in arg_defs.iter().enumerate() { // For all types reachable from the argument type in the fn sig - for generic_inner_ty in arg_def.walk() { + for generic_inner_ty in arg_def.walk(self.tcx) { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { // If the inner type matches the type bound by `Pointer` if TyS::same_type(inner_ty, bound_ty) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 3859b22223c00..6d4234b64a0b3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // code at the moment, because types like `for <'a> fn(&'a ())` do // not *yet* implement `PartialEq`. So for now we leave this here. has_impl - || ty.walk().any(|t| match t.unpack() { + || ty.walk(self.tcx()).any(|t| match t.unpack() { ty::subst::GenericArgKind::Lifetime(_) => false, ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), ty::subst::GenericArgKind::Const(_) => false, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 7ac3ae34637fd..6ec257129e127 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -694,14 +694,15 @@ fn substs_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, substs: ty::Binder<'tcx, SubstsRef<'tcx>>, ) -> impl Iterator> { + let tcx = selcx.tcx(); selcx .infcx() .resolve_vars_if_possible(substs) .skip_binder() // ok because this check doesn't care about regions .iter() .filter(|arg| arg.has_infer_types_or_consts()) - .flat_map(|arg| { - let mut walker = arg.walk(); + .flat_map(move |arg| { + let mut walker = arg.walk(tcx); while let Some(c) = walker.next() { if !c.has_infer_types_or_consts() { walker.visited.remove(&c); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 113ca8b407ea6..84ed21b8fea13 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -278,7 +278,7 @@ fn predicate_references_self( (predicate, sp): (ty::Predicate<'tcx>, Span), ) -> Option { let self_ty = tcx.types.self_param; - let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); + let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into()); match predicate.kind().skip_binder() { ty::PredicateKind::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f8297ee3a0718..d7726e75010f5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -831,7 +831,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut unsizing_params = GrowableBitSet::new_empty(); if tcx.features().relaxed_struct_unsize { - for arg in tail_field_ty.walk() { + for arg in tail_field_ty.walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); } @@ -840,7 +840,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Ensure none of the other fields mention the parameters used // in unsizing. for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { + for arg in tcx.type_of(field.did).walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.remove(i); } @@ -852,7 +852,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } else { let mut found = false; - for arg in tail_field_ty.walk() { + for arg in tail_field_ty.walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); found = true; @@ -868,7 +868,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // by putting it in a query; it would only need the `DefId` as it // looks at declared field types, not anything substituted. for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { + for arg in tcx.type_of(field.did).walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { if unsizing_params.contains(i) { return Err(Unimplemented); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b7853e0bc6f64..8527852f0dab3 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -418,7 +418,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes all the predicates needed to validate that `ty` is WF into `out`. fn compute(&mut self, arg: GenericArg<'tcx>) { - let mut walker = arg.walk(); + let mut walker = arg.walk(self.tcx()); let param_env = self.param_env; let depth = self.recursion_depth; while let Some(arg) = walker.next() { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index b0d644ae028ce..cda8f6402ea63 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -361,7 +361,7 @@ fn well_formed_types_in_env<'tcx>( // constituents are well-formed. NodeKind::InherentImpl => { let self_ty = tcx.type_of(def_id); - inputs.extend(self_ty.walk()); + inputs.extend(self_ty.walk(tcx)); } // In an fn, we assume that the arguments and all their constituents are @@ -370,7 +370,7 @@ fn well_formed_types_in_env<'tcx>( let fn_sig = tcx.fn_sig(def_id); let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); - inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk(tcx))); } NodeKind::Other => (), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2e42d65cce29b..6df2f810ade49 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -394,7 +394,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if self.is_object && has_default { let default_ty = tcx.at(self.span).type_of(param.def_id); let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { + if default_ty.walk(tcx).any(|arg| arg == self_param.into()) { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -1307,7 +1307,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. let references_self = - pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); + pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into()); // If the projection output contains `Self`, force the user to // elaborate it explicitly to avoid a lot of complexity. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 723366be89555..a8e506a46a91f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1525,7 +1525,7 @@ pub(super) fn check_type_params_are_used<'tcx>( return; } - for leaf in ty.walk() { + for leaf in ty.walk(tcx) { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let ty::Param(param) = leaf_ty.kind() { debug!("found use of ty param {:?}", param); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index f65cc429fbd48..b5e62ecc2a062 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have // been `Option`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == predicate.self_ty().into()) { + if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) { Some(i) } else { None diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 6e6ecf6a22b51..1c7f88c0bb611 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -114,7 +114,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for arg in field_ty.walk() { + for arg in field_ty.walk(tcx) { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -306,7 +306,7 @@ pub fn check_explicit_predicates<'tcx>( // 'b`. if let Some(self_ty) = ignored_self_ty { if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.walk().any(|arg| arg == self_ty.into()) { + if ty.walk(tcx).any(|arg| arg == self_ty.into()) { debug!("skipping self ty = {:?}", &ty); continue; } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 5f400d079da2f..5f91bd66c87ad 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -53,7 +53,7 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool { struct EscapeDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, set: HirIdSet, - trait_self_ty: Option>, + trait_self_ty: Option>, too_large_for_stack: u64, } @@ -171,7 +171,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) { + if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index e627b1385bc7d..2d5c4aba14775 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if let Some(init) = local.init; then { let init_ty = cx.typeck_results().expr_ty(init); - let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { + let contains_sync_guard = init_ty.walk(cx.tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => { SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)) }, diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 0f6cd5de761f9..545498a10478d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -49,7 +49,7 @@ pub(super) fn check<'tcx>( if same_item_push_visitor.should_lint(); if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); - let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); + let ty = vec_ty.walk(cx.tcx).nth(1).unwrap().expect_ty(); if cx .tcx .lang_items() diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 283fcf281df18..8e3932f2a8e95 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1950,10 +1950,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // walk the return type and check for Self (this does not check associated types) if let Some(self_adt) = self_ty.ty_adt_def() { - if contains_adt_constructor(ret_ty, self_adt) { + if contains_adt_constructor(cx.tcx, ret_ty, self_adt) { return; } - } else if contains_ty(ret_ty, self_ty) { + } else if contains_ty(cx.tcx, ret_ty, self_ty) { return; } @@ -1964,10 +1964,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { - if contains_adt_constructor(projection_predicate.ty, self_adt) { + if contains_adt_constructor(cx.tcx, projection_predicate.ty, self_adt) { return; } - } else if contains_ty(projection_predicate.ty, self_ty) { + } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) { return; } } @@ -2016,7 +2016,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); - if !contains_ty(ret_ty, self_ty); + if !contains_ty(cx.tcx, ret_ty, self_ty); then { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 251d527c26522..7349b6525f399 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -296,7 +296,7 @@ impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { .fn_sig(def_id) .output() .skip_binder() - .walk() + .walk(self.cx.tcx) .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index 347d858b64026..a9423c05019bd 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -219,7 +219,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + matches!(ty.kind(), ty::Ref(..)) || ty.walk(cx.tcx).any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } impl LateLintPass<'_> for UnnecessarySortBy { diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 71117e967e319..d3a623262521f 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -169,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // // See also https://github.com/rust-lang/rust-clippy/issues/2894. for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) { - if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { + if trait_sem_ty.walk(cx.tcx).any(|inner| inner == self_ty.into()) { let mut visitor = SkipTyCollector::default(); visitor.visit_ty(impl_hir_ty); types_to_skip.extend(visitor.types_to_skip); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 4f0a9f442ed9f..f141ab3280c7e 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1552,7 +1552,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option return Some("slice".into()), rustc_ty::Array(..) => return Some("array".into()), rustc_ty::Tuple(..) => return Some("tuple".into()), @@ -1560,7 +1560,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option, body: &'a Body<'tcx>, msrv: Option<&Ru } fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { - for arg in ty.walk() { + for arg in ty.walk(tcx) { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 3f5c5604d43f5..09f3710334af3 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -10,7 +10,7 @@ use rustc_hir::{TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; +use rustc_middle::ty::{self, TyCtxt, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::DUMMY_SP; @@ -36,8 +36,8 @@ pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } /// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` -pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { - ty.walk().any(|inner| match inner.unpack() { +pub fn contains_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool { + ty.walk(tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -45,8 +45,8 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt /// constructor. -pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { - ty.walk().any(|inner| match inner.unpack() { +pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tcx AdtDef) -> bool { + ty.walk(tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -209,7 +209,7 @@ fn is_normalizable_helper<'tcx>( .iter() .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { + _ => ty.walk(cx.tcx).all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) }, From 80423d6ccac9ba3e1fbdbc1869cdf8778a189deb Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Jul 2021 18:48:07 +0200 Subject: [PATCH 48/52] update `TypeFlags` to deal with missing ct substs --- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../src/infer/canonical/canonicalizer.rs | 2 +- compiler/rustc_infer/src/infer/freshen.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/noop_method_call.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 10 +- compiler/rustc_middle/src/ty/consts/kind.rs | 6 + compiler/rustc_middle/src/ty/erase_regions.rs | 4 +- compiler/rustc_middle/src/ty/flags.rs | 18 ++- compiler/rustc_middle/src/ty/fold.rs | 103 ++++++++++++---- compiler/rustc_middle/src/ty/layout.rs | 6 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- .../rustc_middle/src/ty/structural_impls.rs | 4 + compiler/rustc_middle/src/ty/sty.rs | 20 ++-- compiler/rustc_middle/src/ty/subst.rs | 6 +- compiler/rustc_middle/src/ty/vtable.rs | 5 +- .../borrow_check/type_check/liveness/trace.rs | 2 +- compiler/rustc_mir/src/interpret/util.rs | 24 ++-- .../src/monomorphize/polymorphize.rs | 8 +- compiler/rustc_mir/src/shim.rs | 24 +++- .../rustc_mir/src/transform/const_prop.rs | 11 +- .../rustc_mir/src/transform/inline/cycle.rs | 2 +- compiler/rustc_mir/src/transform/mod.rs | 6 +- .../rustc_mir/src/transform/promote_consts.rs | 1 + compiler/rustc_mir_build/src/build/mod.rs | 10 +- compiler/rustc_symbol_mangling/src/legacy.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 3 +- .../rustc_trait_selection/src/opaque_types.rs | 2 +- .../src/traits/coherence.rs | 2 +- .../src/traits/const_evaluatable.rs | 6 +- .../src/traits/fulfill.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/select/mod.rs | 12 +- compiler/rustc_type_ir/src/lib.rs | 112 +++++++++++------- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 8 +- compiler/rustc_typeck/src/check/wfcheck.rs | 12 +- compiler/rustc_typeck/src/check/writeback.rs | 2 +- compiler/rustc_typeck/src/collect/type_of.rs | 11 +- .../src/impl_wf_check/min_specialization.rs | 2 +- .../src/needless_pass_by_value.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 45 files changed, 307 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 8375d4c7ca561..2e8a960401724 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -499,7 +499,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full - && !impl_self_ty.needs_subst() + && !impl_self_ty.needs_subst(cx.tcx) { Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP)) } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b584801a62de2..b8eefd6890307 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1391,7 +1391,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::Operand(None) => { let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref())); - assert!(!dst_layout.ty.has_erasable_regions()); + assert!(!dst_layout.ty.has_erasable_regions(self.cx.tcx())); let place = PlaceRef::alloca(bx, dst_layout); place.storage_live(bx); self.codegen_transmute_into(bx, src, place); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 3bbc481b61093..e2edd44826717 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -216,7 +216,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut allocate_local = |local| { let decl = &mir.local_decls[local]; let layout = bx.layout_of(fx.monomorphize(decl.ty)); - assert!(!layout.ty.has_erasable_regions()); + assert!(!layout.ty.has_erasable_regions(cx.tcx())); if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { debug!("alloc: {:?} (return place) -> place", local); diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ac953f4305c31..914b1c97c4797 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -479,7 +479,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { { let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::NEEDS_INFER | - TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` + TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_xxx_FREE_REGIONS` TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER } else { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index b3d7876c6e819..10d7cfbbd1207 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { + if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) { return t; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 261f95979083f..a955ed4ea64f0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1614,7 +1614,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ConstEquate(..) | TypeWellFormedFromEnv(..) => continue, }; - if predicate.is_global() { + if predicate.is_global(cx.tcx) { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { lint.build(&format!( "{} bound {} does not depend on any type \ diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 479cc00199f6a..908d847915f88 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { _ => return, }; let substs = cx.typeck_results().node_substs(expr.hir_id); - if substs.needs_subst() { + if substs.needs_subst(cx.tcx) { // We can't resolve on types that require monomorphization, so we don't handle them if // we need to perfom substitution. return; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index da0d2575dcbe3..cac2f9b2fe9d0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -242,6 +242,7 @@ pub struct Body<'tcx> { impl<'tcx> Body<'tcx> { pub fn new( + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, basic_blocks: IndexVec>, source_scopes: IndexVec>, @@ -284,7 +285,7 @@ impl<'tcx> Body<'tcx> { predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), }; - body.is_polymorphic = body.has_param_types_or_consts(); + body.is_polymorphic = body.has_param_types_or_consts(tcx); body } @@ -293,7 +294,10 @@ impl<'tcx> Body<'tcx> { /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. - pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { + pub fn new_cfg_only( + tcx: TyCtxt<'tcx>, + basic_blocks: IndexVec>, + ) -> Self { let mut body = Body { phase: MirPhase::Build, source: MirSource::item(DefId::local(CRATE_DEF_INDEX)), @@ -311,7 +315,7 @@ impl<'tcx> Body<'tcx> { predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), }; - body.is_polymorphic = body.has_param_types_or_consts(); + body.is_polymorphic = body.has_param_types_or_consts(tcx); body } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ab2c57ac605b7..174c35dbc7187 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -12,6 +12,12 @@ use rustc_target::abi::Size; use super::ScalarInt; /// An unevaluated, potentially generic, constant. +/// +/// If `substs_` is `None` it means that this anon const +/// still has its default substs. +/// +/// We check for all possible substs in `fn default_anon_const_substs`, +/// so refer to that check for more info. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] pub struct Unevaluated<'tcx> { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 759d1a017aa2a..63eb55ed1a620 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -21,7 +21,9 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<'tcx>, { // If there's nothing to erase avoid performing the query at all - if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { + if !value + .has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS) + { return value; } debug!("erase_regions({:?})", value); diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index e1985ea74ae79..54c20599f7e38 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -34,6 +34,12 @@ impl FlagComputation { result.flags } + pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags { + let mut result = FlagComputation::new(); + result.add_unevaluated_const(uv); + result.flags + } + fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -91,7 +97,7 @@ impl FlagComputation { &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_TY_PARAM); + self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } @@ -288,7 +294,7 @@ impl FlagComputation { self.add_bound_var(debruijn); } ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_CT_PARAM); + self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Placeholder(_) => { @@ -301,8 +307,12 @@ impl FlagComputation { } fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) { - // TODO - self.add_substs(ct.substs_.unwrap()); + if let Some(substs) = ct.substs_ { + self.add_substs(substs); + } else { + self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_flags(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS); + } self.add_flags(TypeFlags::HAS_CT_PROJECTION); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 6e70e8ddaed80..0c5e292e6eb5b 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -74,8 +74,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_vars_bound_at_or_above(ty::INNERMOST) } + fn definitely_has_type_flags(&self, tcx: TyCtxt<'tcx>, flags: TypeFlags) -> bool { + self.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(tcx), flags }).break_value() + == Some(FoundFlags) + } + fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) + self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() + == Some(FoundFlags) } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -86,8 +92,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } - fn has_param_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) + fn has_potential_param_types_or_consts(&self) -> bool { + self.has_type_flags( + TypeFlags::HAS_KNOWN_TY_PARAM + | TypeFlags::HAS_KNOWN_CT_PARAM + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS, + ) + } + fn has_param_types_or_consts(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags( + tcx, + TypeFlags::HAS_KNOWN_TY_PARAM | TypeFlags::HAS_KNOWN_CT_PARAM, + ) } fn has_infer_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_INFER) @@ -108,13 +124,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { | TypeFlags::HAS_CT_PLACEHOLDER, ) } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) + fn potentially_needs_subst(&self) -> bool { + self.has_type_flags( + TypeFlags::KNOWN_NEEDS_SUBST | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS, + ) + } + fn needs_subst(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::KNOWN_NEEDS_SUBST) } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + fn has_free_regions(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) } fn has_erased_regions(&self) -> bool { @@ -122,15 +143,25 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + fn has_erasable_regions(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) + } + + /// Indicates whether this value definitely references only 'global' + /// generic parameters that are the same regardless of what fn we are + /// in. This is used for caching. + /// + /// Note that this function is pessimistic and may incorrectly return + /// `false`. + fn is_known_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_POTENTIAL_FREE_LOCAL_NAMES) } /// Indicates whether this value references only 'global' /// generic parameters that are the same regardless of what fn we are /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) + fn is_global(&self, tcx: TyCtxt<'tcx>) -> bool { + !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES) } /// True if there are any late-bound regions @@ -217,6 +248,10 @@ pub trait TypeVisitor<'tcx>: Sized { c.super_visit_with(self) } + fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + uv.super_visit_with(self) + } + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow { p.super_visit_with(self) } @@ -369,7 +404,7 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions - if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { + if ty.flags().intersects(TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { ty.super_visit_with(self) } else { ControlFlow::CONTINUE @@ -1078,23 +1113,19 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { struct FoundFlags; // FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { +struct HasTypeFlagsVisitor<'tcx> { + tcx: Option>, flags: ty::TypeFlags, } -impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { +impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; fn tcx_for_anon_const_substs(&self) -> Option> { - // TypeFlagsVisitor must not look into the default anon const substs - // as that would cause cycle errors, but we do care about them for - // some flags. - // - // We therefore have to be very careful here. - None + self.tcx } #[inline] - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, @@ -1103,6 +1134,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { ); if t.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + t.super_visit_with(self) } else { ControlFlow::CONTINUE } @@ -1125,6 +1161,26 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + c.super_visit_with(self) + } else { + ControlFlow::CONTINUE + } + } + + fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + let flags = FlagComputation::for_unevaluated_const(uv); + debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + uv.super_visit_with(self) } else { ControlFlow::CONTINUE } @@ -1138,6 +1194,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { ); if predicate.inner.flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + predicate.super_visit_with(self) } else { ControlFlow::CONTINUE } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 95ea38d32b695..9cbad3e5aa137 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1727,7 +1727,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff // resulting from the final codegen session. - if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() { + if layout.ty.has_param_types_or_consts(self.tcx) + || !self.param_env.caller_bounds().is_empty() + { return; } @@ -1894,7 +1896,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); match tail.kind() { ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.has_param_types_or_consts()); + debug_assert!(tail.has_param_types_or_consts(tcx)); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a6aff42479069..7971e8364067a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1251,7 +1251,7 @@ impl<'tcx> ParamEnv<'tcx> { Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, Reveal::All => { - if value.is_global() { + if value.is_known_global() { ParamEnvAnd { param_env: self.without_caller_bounds(), value } } else { ParamEnvAnd { param_env: self, value } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 820d858e3c5a1..e5bea32582bc4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1201,7 +1201,9 @@ pub trait PrettyPrinter<'tcx>: // // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. - (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { + (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) + if !ty.has_potential_param_types_or_consts() => + { let contents = self.tcx().destructure_const( ty::ParamEnv::reveal_all() .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 81ac5825473ee..b539e756c6126 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1079,6 +1079,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { } } + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_unevaluated_const(*self) + } + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { if let Some(tcx) = visitor.tcx_for_anon_const_substs() { self.substs(tcx).visit_with(visitor) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6a7e349819afd..85aed6273698d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1562,26 +1562,26 @@ impl RegionKind { match *self { ty::ReVar(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; } ty::RePlaceholder(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } ty::ReEarlyBound(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - flags = flags | TypeFlags::HAS_RE_PARAM; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM; } ty::ReFree { .. } => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; } ty::ReEmpty(_) | ty::ReStatic => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; } ty::ReLateBound(..) => { flags = flags | TypeFlags::HAS_RE_LATE_BOUND; diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 9b8d22d8eafce..a8234db79ef0d 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { + if !t.potentially_needs_subst() { return t; } @@ -497,10 +497,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !c.needs_subst() { - return c; - } - if let ty::ConstKind::Param(p) = c.val { self.const_for_param(p, c) } else { diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 78109fc7b5713..a8ab459e86e3a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -38,7 +38,8 @@ impl<'tcx> TyCtxt<'tcx> { // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 assert!( - !ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst()) + !ty.needs_subst(tcx) + && poly_trait_ref.map_or(true, |trait_ref| !trait_ref.needs_subst(tcx)) ); let param_env = ty::ParamEnv::reveal_all(); let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { @@ -81,7 +82,7 @@ impl<'tcx> TyCtxt<'tcx> { VtblEntry::Vacant => continue, VtblEntry::Method(def_id, substs) => { // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 - assert!(!substs.needs_subst()); + assert!(!substs.needs_subst(tcx)); // Prepare the fn ptr we write into the vtable. let instance = diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs index f04736e04a053..67b354bd2a16f 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs @@ -171,7 +171,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { for (local, location) in drop_used { if !live_locals.contains(&local) { let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions() { + if local_ty.has_free_regions(self.cx.typeck.tcx()) { self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); } } diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index b9d6e002e2db1..37c13c2d42aec 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -9,7 +9,7 @@ where T: TypeFoldable<'tcx>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.needs_subst() { + if !ty.potentially_needs_subst() { return Ok(()); } @@ -25,19 +25,8 @@ where Some(self.tcx) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { - if !c.needs_subst() { - return ControlFlow::CONTINUE; - } - - match c.val { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } - } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.needs_subst() { + if !ty.potentially_needs_subst() { return ControlFlow::CONTINUE; } @@ -54,7 +43,7 @@ where let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - match (is_used, subst.needs_subst()) { + match (is_used, subst.needs_subst(self.tcx)) { // Just in case there are closures or generators within this subst, // recurse. (true, true) => return subst.super_visit_with(self), @@ -77,6 +66,13 @@ where _ => ty.super_visit_with(self), } } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { + match c.val { + ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), + _ => c.super_visit_with(self), + } + } } let mut vis = UsedParamsNeedSubstVisitor { tcx }; diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 204b3b135228f..4d69fae463231 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.has_param_types_or_consts() { + if !c.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -325,7 +325,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.has_param_types_or_consts() { + if !ty.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -367,7 +367,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.has_param_types_or_consts() { + if !c.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -385,7 +385,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { #[instrument(skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.has_param_types_or_consts() { + if !ty.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index 796d024771d7f..a6cb2d82cac42 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -163,7 +163,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); let mut body = - new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); + new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); if ty.is_some() { // The first argument (index 0), but add 1 for the return value. @@ -202,6 +202,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) } fn new_body<'tcx>( + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, basic_blocks: IndexVec>, local_decls: IndexVec>, @@ -209,6 +210,7 @@ fn new_body<'tcx>( span: Span, ) -> Body<'tcx> { Body::new( + tcx, source, basic_blocks, IndexVec::from_elem_n( @@ -353,7 +355,14 @@ impl CloneShimBuilder<'tcx> { self.def_id, self.sig.inputs_and_output[0], )); - new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span) + new_body( + self.tcx, + source, + self.blocks, + self.local_decls, + self.sig.inputs().len(), + self.span, + ) } fn source_info(&self) -> SourceInfo { @@ -851,8 +860,14 @@ fn build_call_shim<'tcx>( block(&mut blocks, vec![], TerminatorKind::Resume, true); } - let mut body = - new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span); + let mut body = new_body( + tcx, + MirSource::from_instance(instance), + blocks, + local_decls, + sig.inputs().len(), + span, + ); if let Abi::RustCall = sig.abi { body.spread_arg = Some(Local::new(sig.inputs().len())); @@ -917,6 +932,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let source = MirSource::item(ctor_id); let body = new_body( + tcx, source, IndexVec::from_elem_n(start_block, 1), local_decls, diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 8d819bf44ec79..78cb3e7a6723c 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -120,7 +120,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { .predicates_of(def_id.to_def_id()) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None }); if traits::impossible_predicates( tcx, traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), @@ -132,6 +132,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { trace!("ConstProp starting for {:?}", def_id); let dummy_body = &Body::new( + tcx, body.source, body.basic_blocks().clone(), body.source_scopes.clone(), @@ -468,7 +469,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns the value, if any, of evaluating `c`. fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option> { // FIXME we need to revisit this for #67176 - if c.needs_subst() { + if c.needs_subst(self.tcx) { return None; } @@ -488,9 +489,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { }) => true, // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. - _ => c.literal.needs_subst(), + _ => c.literal.needs_subst(*tcx), }, - ConstantKind::Val(_, ty) => ty.needs_subst(), + ConstantKind::Val(_, ty) => ty.needs_subst(*tcx), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -720,7 +721,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } // FIXME we need to revisit this for #67176 - if rvalue.needs_subst() { + if rvalue.needs_subst(self.tcx) { return None; } diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs index c9eafafff57cd..46628b928de92 100644 --- a/compiler/rustc_mir/src/transform/inline/cycle.rs +++ b/compiler/rustc_mir/src/transform/inline/cycle.rs @@ -89,7 +89,7 @@ crate fn mir_callgraph_reachable( // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. - if callee.needs_subst() { + if callee.needs_subst(tcx) { continue; } } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 5c201594ddd89..e04a9611ae1c5 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -397,7 +397,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - } } - debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); + debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE"); body } @@ -588,7 +588,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); run_optimization_passes(tcx, &mut body); - debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); + debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR"); body } @@ -615,7 +615,7 @@ fn promoted_mir<'tcx>( run_post_borrowck_cleanup_passes(tcx, body); } - debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR"); + debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR"); tcx.arena.alloc(promoted) } diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 428778a6718e2..a4a9df7b7c26f 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -992,6 +992,7 @@ pub fn promote_candidates<'tcx>( scope.parent_scope = None; let promoted = Body::new( + tcx, body.source, // `promoted` gets filled in below IndexVec::new(), IndexVec::from_elem_n(scope, 1), diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 60cfd73b19a6e..f218a60c256a3 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -241,10 +241,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // The exception is `body.user_type_annotations`, which is used unmodified // by borrow checking. debug_assert!( - !(body.local_decls.has_free_regions() - || body.basic_blocks().has_free_regions() - || body.var_debug_info.has_free_regions() - || body.yield_ty().has_free_regions()), + !(body.local_decls.has_free_regions(tcx) + || body.basic_blocks().has_free_regions(tcx) + || body.var_debug_info.has_free_regions(tcx) + || body.yield_ty().has_free_regions(tcx)), "Unexpected free regions in MIR: {:?}", body, ); @@ -812,6 +812,7 @@ fn construct_error<'a, 'tcx>( cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); let mut body = Body::new( + tcx, MirSource::item(def.did.to_def_id()), cfg.basic_blocks, source_scopes, @@ -900,6 +901,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Body::new( + self.tcx, MirSource::item(self.def_id), self.cfg.basic_blocks, self.source_scopes, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0c64fe6ea60a9..2917eef63c2dd 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -108,7 +108,7 @@ fn get_symbol_hash<'tcx>( // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); + assert!(!item_type.has_erasable_regions(tcx)); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { item_type.hash_stable(hcx, &mut hasher); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 14442806fc0b7..b1d042c988a50 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -286,7 +286,8 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Encode impl generic params if the substitutions contain parameters (implying // polymorphization is enabled) and this isn't an inherent impl. - if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { + if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts(self.tcx)) + { self = self.path_generic_args( |this| { this.path_append_ns( diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 71b18b55cfa0d..74a4ce30ef9fa 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -655,7 +655,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions - if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9bb4af16a8f53..6ab079ad404d5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -391,7 +391,7 @@ fn orphan_check_trait_ref<'tcx>( ) -> Result<(), OrphanCheckErr<'tcx>> { debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); - if trait_ref.needs_infer() && trait_ref.needs_subst() { + if trait_ref.needs_infer() && trait_ref.needs_subst(tcx) { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", trait_ref diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 2f1e7e9d509b4..2cc74ca2abb4b 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -91,7 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; - } else if leaf.has_param_types_or_consts() { + } else if leaf.has_param_types_or_consts(tcx) { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } @@ -101,7 +101,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; - } else if ty.has_param_types_or_consts() { + } else if ty.has_param_types_or_consts(tcx) { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } @@ -158,7 +158,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let concrete = infcx.const_eval_resolve(param_env, ty::Unevaluated::new(def, substs), Some(span)); - if concrete.is_ok() && substs.has_param_types_or_consts() { + if concrete.is_ok() && substs.has_param_types_or_consts(infcx.tcx) { match infcx.tcx.def_kind(def.did) { DefKind::AnonConst => { let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6ec257129e127..1478c56bd15ec 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -618,7 +618,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { stalled_on: &mut Vec>, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx(); - if obligation.predicate.is_global() { + if obligation.predicate.is_known_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3a80e720e8c4b..91790967fdae4 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -447,7 +447,7 @@ fn subst_and_check_impossible_predicates<'tcx>( debug!("subst_and_check_impossible_predicates(key={:?})", key); let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - predicates.retain(|predicate| !predicate.needs_subst()); + predicates.retain(|predicate| !predicate.needs_subst(tcx)); let result = impossible_predicates(tcx, predicates); debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1a4fe14e689a2..b0eba1b133ee3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -493,7 +493,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }, ty::PredicateKind::TypeOutlives(pred) => { - if pred.0.is_global() { + if pred.0.is_known_global() { Ok(EvaluatedToOk) } else { Ok(EvaluatedToOkModuloRegions) @@ -644,8 +644,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "evaluate_trait_predicate_recursively"); if !self.intercrate - && obligation.is_global() - && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) + && obligation.is_global(self.tcx()) + && obligation + .param_env + .caller_bounds() + .iter() + .all(|bound| bound.needs_subst(self.tcx())) { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear @@ -1359,7 +1363,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); + |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // and `DiscriminantKindCandidate` to anything else. diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 2d102127dd9d6..c405bbe2d1f53 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -19,94 +19,116 @@ bitflags! { // Does this have parameters? Used to determine whether substitution is // required. /// Does this have `Param`? - const HAS_TY_PARAM = 1 << 0; + const HAS_KNOWN_TY_PARAM = 1 << 0; /// Does this have `ReEarlyBound`? - const HAS_RE_PARAM = 1 << 1; + const HAS_KNOWN_RE_PARAM = 1 << 1; /// Does this have `ConstKind::Param`? - const HAS_CT_PARAM = 1 << 2; + const HAS_KNOWN_CT_PARAM = 1 << 2; - const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits; + const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_RE_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits; /// Does this have `Infer`? - const HAS_TY_INFER = 1 << 3; + const HAS_TY_INFER = 1 << 3; /// Does this have `ReVar`? - const HAS_RE_INFER = 1 << 4; + const HAS_RE_INFER = 1 << 4; /// Does this have `ConstKind::Infer`? - const HAS_CT_INFER = 1 << 5; + const HAS_CT_INFER = 1 << 5; /// Does this have inference variables? Used to determine whether /// inference is required. - const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits; + const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits; /// Does this have `Placeholder`? - const HAS_TY_PLACEHOLDER = 1 << 6; + const HAS_TY_PLACEHOLDER = 1 << 6; /// Does this have `RePlaceholder`? - const HAS_RE_PLACEHOLDER = 1 << 7; + const HAS_RE_PLACEHOLDER = 1 << 7; /// Does this have `ConstKind::Placeholder`? - const HAS_CT_PLACEHOLDER = 1 << 8; + const HAS_CT_PLACEHOLDER = 1 << 8; /// `true` if there are "names" of regions and so forth /// that are local to a particular fn/inferctxt - const HAS_FREE_LOCAL_REGIONS = 1 << 9; + const HAS_KNOWN_FREE_LOCAL_REGIONS = 1 << 9; /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits - // We consider 'freshened' types and constants - // to depend on a particular fn. - // The freshening process throws away information, - // which can make things unsuitable for use in a global - // cache. Note that there is no 'fresh lifetime' flag - - // freshening replaces all lifetimes with `ReErased`, - // which is different from how types/const are freshened. - | TypeFlags::HAS_TY_FRESH.bits - | TypeFlags::HAS_CT_FRESH.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + const HAS_KNOWN_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + // We consider 'freshened' types and constants + // to depend on a particular fn. + // The freshening process throws away information, + // which can make things unsuitable for use in a global + // cache. Note that there is no 'fresh lifetime' flag - + // freshening replaces all lifetimes with `ReErased`, + // which is different from how types/const are freshened. + | TypeFlags::HAS_TY_FRESH.bits + | TypeFlags::HAS_CT_FRESH.bits + | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits; + + const HAS_POTENTIAL_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES.bits + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits; /// Does this have `Projection`? - const HAS_TY_PROJECTION = 1 << 10; + const HAS_TY_PROJECTION = 1 << 10; /// Does this have `Opaque`? - const HAS_TY_OPAQUE = 1 << 11; + const HAS_TY_OPAQUE = 1 << 11; /// Does this have `ConstKind::Unevaluated`? - const HAS_CT_PROJECTION = 1 << 12; + const HAS_CT_PROJECTION = 1 << 12; /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_CT_PROJECTION.bits; + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits; /// Is an error type/const reachable? - const HAS_ERROR = 1 << 13; + const HAS_ERROR = 1 << 13; /// Does this have any region that "appears free" in the type? /// Basically anything but `ReLateBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 14; + const HAS_KNOWN_FREE_REGIONS = 1 << 14; + + const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits; /// Does this have any `ReLateBound` regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 15; + const HAS_RE_LATE_BOUND = 1 << 15; /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 16; + const HAS_RE_ERASED = 1 << 16; /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 17; + /// + /// Note that this flag being set is not a guarantee, as it is also + /// set if there are any anon consts with unknown default substs. + const STILL_FURTHER_SPECIALIZABLE = 1 << 17; /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 18; + const HAS_TY_FRESH = 1 << 18; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 19; + const HAS_CT_FRESH = 1 << 19; + + /// Does this value have unknown default anon const substs. + /// + /// For more details refer to... + /// FIXME(@lcnr): ask me for now, still have to write all of this. + const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS = 1 << 20; + /// Flags which can be influenced by default anon const substs. + const MAY_NEED_DEFAULT_CONST_SUBSTS = TypeFlags::HAS_KNOWN_RE_PARAM.bits + | TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits + | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits + | TypeFlags::HAS_KNOWN_FREE_REGIONS.bits; + } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 6df2f810ade49..75d2f336ac2c8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2149,7 +2149,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); // Try to evaluate any array length constants. let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); - if forbid_generic && normalized_ty.needs_subst() { + if forbid_generic && normalized_ty.needs_subst(tcx) { let mut err = tcx.sess.struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4ed07ba358de3..275c955b15231 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -239,7 +239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tag(), ); - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, @@ -513,7 +513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.to_ty(ast_ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - if Self::can_contain_user_lifetime_bounds(ty) { + if self.can_contain_user_lifetime_bounds(ty) { let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); @@ -558,11 +558,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // reader, although I have my doubts). Also pass in types with inference // types, because they may be repeated. Other sorts of things are already // sufficiently enforced with erased regions. =) - fn can_contain_user_lifetime_bounds(t: T) -> bool + fn can_contain_user_lifetime_bounds(&self, t: T) -> bool where T: TypeFoldable<'tcx>, { - t.has_free_regions() || t.has_projections() || t.has_infer_types() + t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types() } pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 9d783991c6d38..3a0b24ae61296 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -730,7 +730,7 @@ fn check_where_clauses<'tcx, 'fcx>( // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. - if !ty.needs_subst() { + if !ty.needs_subst(tcx) { fcx.register_wf_obligation( ty.into(), tcx.def_span(param.def_id), @@ -746,7 +746,7 @@ fn check_where_clauses<'tcx, 'fcx>( // for `struct Foo` // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id); - if !default_ct.needs_subst() { + if !default_ct.needs_subst(tcx) { fcx.register_wf_obligation( default_ct.into(), tcx.def_span(param.def_id), @@ -780,7 +780,7 @@ fn check_where_clauses<'tcx, 'fcx>( if is_our_default(param) { let default_ty = tcx.type_of(param.def_id); // ... and it's not a dependent default, ... - if !default_ty.needs_subst() { + if !default_ty.needs_subst(tcx) { // ... then substitute it with the default. return default_ty.into(); } @@ -793,7 +793,7 @@ fn check_where_clauses<'tcx, 'fcx>( if is_our_default(param) { let default_ct = tcx.const_param_default(param.def_id); // ... and it's not a dependent default, ... - if !default_ct.needs_subst() { + if !default_ct.needs_subst(tcx) { // ... then substitute it with the default. return default_ct.into(); } @@ -842,7 +842,7 @@ fn check_where_clauses<'tcx, 'fcx>( let substituted_pred = pred.subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. - if substituted_pred.has_param_types_or_consts() + if substituted_pred.has_param_types_or_consts(tcx) || param_count.params.len() > 1 || has_region { @@ -1329,7 +1329,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { for obligation in implied_obligations { let pred = obligation.predicate; // Match the existing behavior. - if pred.is_global() && !pred.has_late_bound_regions() { + if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() { let pred = fcx.normalize_associated_types_in(span, pred); let obligation = traits::Obligation::new( traits::ObligationCause::new(span, id, traits::TrivialBound), diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 0aa059b7de80f..deb2f147c5451 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -130,7 +130,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions()); + assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx())); self.typeck_results.node_types_mut().insert(hir_id, ty); } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 8459a3b248ee0..67cdd8457465c 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -269,7 +269,16 @@ fn get_path_containing_arg_in_pat<'hir>( } pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { - InternalSubsts::identity_for_item(tcx, def_id) + let substs = InternalSubsts::identity_for_item(tcx, def_id); + // We only expect the following lifetimes, types and constants as default substs. + // + // Getting this wrong can lead to ICE and unsoundness, so we assert it here. + for arg in substs.iter().flat_map(|s| s.walk(tcx)) { + let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS + | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE; + assert!(!arg.has_type_flags(!allowed_flags)); + } + substs } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 1f3996c0646cc..5c3665d19e222 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -363,7 +363,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc match predicate.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if predicate.is_global() => (), + _ if predicate.is_global(tcx) => (), // We allow specializing on explicitly marked traits with no associated // items. ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 57fd03f4e12a6..f2670de08d4bc 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) - .filter(|p| !p.is_global()) + .filter(|p| !p.is_global(cx.tcx)) .filter_map(|obligation| { // Note that we do not want to deal with qualified predicates here. match obligation.predicate.kind().no_bound_vars() { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f141ab3280c7e..bd08d73e0d7b9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1506,7 +1506,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates_of(did) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|(p, _)| if p.is_global(cx.tcx) { Some(*p) } else { None }); traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) From 3ea3257fcb3cc937ad251cb55f16ec899071379e Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Jul 2021 12:13:25 +0200 Subject: [PATCH 49/52] don't just compare `ty::Const` --- compiler/rustc_infer/src/infer/combine.rs | 2 + compiler/rustc_middle/src/ty/fold.rs | 40 +++++++++++++++++++ .../rustc_middle/src/ty/structural_impls.rs | 4 ++ 3 files changed, 46 insertions(+) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 6065bb02d681d..79e885546c331 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -129,6 +129,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { where R: ConstEquateRelation<'tcx>, { + let a = self.tcx.expose_default_const_substs(a); + let b = self.tcx.expose_default_const_substs(b); debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); if a == b { return Ok(a); diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 0c5e292e6eb5b..b249dc8d6f92f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -213,6 +213,10 @@ pub trait TypeFolder<'tcx>: Sized { c.super_fold_with(self) } + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + p.super_fold_with(self) + } + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { bug!("most type folders should not be folding MIR datastructures: {:?}", c) } @@ -1205,6 +1209,42 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } } +impl<'tcx> TyCtxt<'tcx> { + /// This is a HACK(const_generics) and should probably not be needed. + /// Might however be perf relevant, so who knows. + /// + /// FIXME(@lcnr): explain this function a bit more + pub fn expose_default_const_substs>(self, v: T) -> T { + v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }) + } +} + +struct ExposeDefaultConstSubstsFolder<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + ty.super_fold_with(self) + } else { + ty + } + } + + fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + pred.super_fold_with(self) + } else { + pred + } + } +} + /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index b539e756c6126..911d130aed87e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -967,6 +967,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_predicate(self) + } + fn super_fold_with>(self, folder: &mut F) -> Self { let new = self.inner.kind.fold_with(folder); folder.tcx().reuse_or_mk_predicate(self, new) From d823155244a243e4ef7ff8c272f876c154a21a56 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Jul 2021 13:03:29 +0200 Subject: [PATCH 50/52] check for cycles in `default_anon_const_substs` --- compiler/rustc_typeck/src/collect/type_of.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 67cdd8457465c..d4046d47ffedb 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -269,6 +269,11 @@ fn get_path_containing_arg_in_pat<'hir>( } pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { + let generics = tcx.generics_of(def_id); + if let Some(parent) = generics.parent { + let _cycle_check = tcx.predicates_of(parent); + } + let substs = InternalSubsts::identity_for_item(tcx, def_id); // We only expect the following lifetimes, types and constants as default substs. // From 4b8eae1079aa593ef8bb5d0cf723316746e0b94f Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Jul 2021 13:52:43 +0200 Subject: [PATCH 51/52] use `ty::Unevaluated` instead of def substs pair --- compiler/rustc_middle/src/query/mod.rs | 5 +- compiler/rustc_middle/src/ty/consts/kind.rs | 2 +- compiler/rustc_middle/src/ty/flags.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- compiler/rustc_middle/src/ty/relate.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 8 +-- compiler/rustc_privacy/src/lib.rs | 4 +- compiler/rustc_query_impl/src/keys.rs | 11 ++-- .../src/traits/const_evaluatable.rs | 53 ++++++++----------- .../src/traits/error_reporting/mod.rs | 4 +- .../src/traits/fulfill.rs | 14 +++-- .../src/traits/object_safety.rs | 4 +- .../src/traits/select/mod.rs | 10 ++-- .../rustc_trait_selection/src/traits/wf.rs | 11 ++-- compiler/rustc_typeck/src/check/wfcheck.rs | 4 +- compiler/rustc_typeck/src/collect.rs | 7 +-- 17 files changed, 64 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 33eef0bd4f197..54f4745c6f3db 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -297,12 +297,11 @@ rustc_queries! { } query try_unify_abstract_consts(key: ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>) + ty::Unevaluated<'tcx>, ty::Unevaluated<'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) + tcx.def_path_str(key.0.def.did), tcx.def_path_str(key.1.def.did) } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 174c35dbc7187..b1f6a61277662 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -18,7 +18,7 @@ use super::ScalarInt; /// /// We check for all possible substs in `fn default_anon_const_substs`, /// so refer to that check for more info. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable)] pub struct Unevaluated<'tcx> { pub def: ty::WithOptConstParam, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 54c20599f7e38..31f299604b9ba 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -248,8 +248,8 @@ impl FlagComputation { ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { self.add_substs(substs); } - ty::PredicateKind::ConstEvaluatable(_def_id, substs) => { - self.add_substs(substs); + ty::PredicateKind::ConstEvaluatable(uv) => { + self.add_unevaluated_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7971e8364067a..1ea01e4f61dd1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -401,7 +401,7 @@ crate struct PredicateInner<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateInner<'_>, 48); +static_assert_size!(PredicateInner<'_>, 56); #[derive(Clone, Copy, Lift)] pub struct Predicate<'tcx> { @@ -483,7 +483,7 @@ pub enum PredicateKind<'tcx> { Subtype(SubtypePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::WithOptConstParam, SubstsRef<'tcx>), + ConstEvaluatable(ty::Unevaluated<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e5bea32582bc4..e9d9e99959fb7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2220,8 +2220,8 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(def, substs) => { - p!("the constant `", print_value_path(def.did, substs), "` can be evaluated") + ty::PredicateKind::ConstEvaluatable(uv) => { + p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3514027cc82f9..5599875da88f8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -552,7 +552,7 @@ pub fn super_relate_consts>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().const_evaluatable_checked => { - tcx.try_unify_abstract_consts(((au.def, au.substs(tcx)), (bu.def, bu.substs(tcx)))) + tcx.try_unify_abstract_consts((au, bu)) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 911d130aed87e..f8ebd3dc7696b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -191,8 +191,8 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) + ty::PredicateKind::ConstEvaluatable(uv) => { + write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::TypeWellFormedFromEnv(ty) => { @@ -441,8 +441,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ObjectSafe(trait_def_id) => { Some(ty::PredicateKind::ObjectSafe(trait_def_id)) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs)) + ty::PredicateKind::ConstEvaluatable(uv) => { + tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv)) } ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9d44c0c873554..c85194213a0b4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -133,11 +133,11 @@ where ty.visit_with(self) } ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, - ty::PredicateKind::ConstEvaluatable(defs, substs) + ty::PredicateKind::ConstEvaluatable(uv) if self.def_id_visitor.tcx().features().const_evaluatable_checked => { let tcx = self.def_id_visitor.tcx(); - if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) { + if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) { self.visit_abstract_const_expr(tcx, ct)?; } ControlFlow::CONTINUE diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1993e0a602fa5..092c60050fb65 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -217,18 +217,13 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } -impl<'tcx> Key - for ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>), - ) -{ +impl<'tcx> Key for (ty::Unevaluated<'tcx>, ty::Unevaluated<'tcx>) { #[inline(always)] fn query_crate_is_local(&self) -> bool { - (self.0).0.did.krate == LOCAL_CRATE + (self.0).def.did.krate == LOCAL_CRATE } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - (self.0).0.did.default_span(tcx) + (self.0).def.did.default_span(tcx) } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 2cc74ca2abb4b..80c824565d226 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use std::cmp; @@ -29,26 +29,20 @@ use std::ops::ControlFlow; /// Check if a given constant can be evaluated. pub fn is_const_evaluatable<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - def: ty::WithOptConstParam, - substs: SubstsRef<'tcx>, + uv: ty::Unevaluated<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { - debug!("is_const_evaluatable({:?}, {:?})", def, substs); + debug!("is_const_evaluatable({:?})", uv); if infcx.tcx.features().const_evaluatable_checked { let tcx = infcx.tcx; - match AbstractConst::new(tcx, def, substs)? { + match AbstractConst::new(tcx, uv)? { // We are looking at a generic abstract constant. Some(ct) => { for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => { - if b_def == def && b_substs == substs { - debug!("is_const_evaluatable: caller_bound ~~> ok"); - return Ok(()); - } - - if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? { + ty::PredicateKind::ConstEvaluatable(uv) => { + if let Some(b_ct) = AbstractConst::new(tcx, uv)? { // 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` @@ -134,7 +128,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } let future_compat_lint = || { - if let Some(local_def_id) = def.did.as_local() { + if let Some(local_def_id) = uv.def.did.as_local() { infcx.tcx.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), @@ -155,13 +149,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // and hopefully soon change this to an error. // // See #74595 for more details about this. - let concrete = - infcx.const_eval_resolve(param_env, ty::Unevaluated::new(def, substs), Some(span)); + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); - if concrete.is_ok() && substs.has_param_types_or_consts(infcx.tcx) { - match infcx.tcx.def_kind(def.did) { + if concrete.is_ok() && uv.substs(infcx.tcx).has_param_types_or_consts(infcx.tcx) { + match infcx.tcx.def_kind(uv.def.did) { DefKind::AnonConst => { - let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def); + let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); if mir_body.is_polymorphic { future_compat_lint(); @@ -173,7 +166,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( debug!(?concrete, "is_const_evaluatable"); match concrete { - Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() { + Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() { true => NotConstEvaluatable::MentionsInfer, false => NotConstEvaluatable::MentionsParam, }), @@ -198,15 +191,14 @@ pub struct AbstractConst<'tcx> { pub substs: SubstsRef<'tcx>, } -impl AbstractConst<'tcx> { +impl<'tcx> AbstractConst<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, - substs: SubstsRef<'tcx>, + uv: ty::Unevaluated<'tcx>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(def)?; - debug!("AbstractConst::new({:?}) = {:?}", def, inner); - Ok(inner.map(|inner| AbstractConst { inner, substs })) + let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + debug!("AbstractConst::new({:?}) = {:?}", uv, inner); + Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } pub fn from_const( @@ -214,7 +206,7 @@ impl AbstractConst<'tcx> { ct: &ty::Const<'tcx>, ) -> Result>, ErrorReported> { match ct.val { - ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.def, uv.substs(tcx)), + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv), ty::ConstKind::Error(_) => Err(ErrorReported), _ => Ok(None), } @@ -564,14 +556,11 @@ pub(super) fn mir_abstract_const<'tcx>( pub(super) fn try_unify_abstract_consts<'tcx>( tcx: TyCtxt<'tcx>, - ((a, a_substs), (b, b_substs)): ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>), - ), + (a, b): (ty::Unevaluated<'tcx>, ty::Unevaluated<'tcx>), ) -> bool { (|| { - if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { - if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { + if let Some(a) = AbstractConst::new(tcx, a)? { + if let Some(b) = AbstractConst::new(tcx, b)? { return Ok(try_unify(tcx, a, b)); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5c4aef529e5ac..52bed225a57af 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -804,10 +804,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(def, _) => { + ty::PredicateKind::ConstEvaluatable(uv) => { let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(def.did); + let const_span = self.tcx.def_span(uv.def.did); match self.tcx.sess.source_map().span_to_snippet(const_span) { Ok(snippet) => err.help(&format!( "try adding a `where` bound using this expression: `where [(); {}]:`", diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1478c56bd15ec..4bbab6f700a82 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -489,11 +489,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(uv) => { match const_evaluatable::is_const_evaluatable( self.selcx.infcx(), - def_id, - substs, + uv, obligation.param_env, obligation.cause.span, ) { @@ -501,7 +500,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.extend( - substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg), + uv.substs(infcx.tcx) + .iter() + .filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); ProcessResult::Unchanged } @@ -525,10 +526,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if tcx.try_unify_abstract_consts(( - (a.def, a.substs(tcx)), - (b.def, b.substs(tcx)), - )) { + if tcx.try_unify_abstract_consts((a, b)) { return ProcessResult::Changed(vec![]); } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 84ed21b8fea13..1df707565f4a4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -852,12 +852,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow { - if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() { + if let ty::PredicateKind::ConstEvaluatable(ct) = pred.kind().skip_binder() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to // take a `ty::Const` instead. use rustc_middle::mir::abstract_const::Node; - if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { + if let Ok(Some(ct)) = AbstractConst::new(self.tcx, ct) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b0eba1b133ee3..e09d2b8adf179 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -547,11 +547,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(uv) => { match const_evaluatable::is_const_evaluatable( self.infcx, - def_id, - substs, + uv, obligation.param_env, obligation.cause.span, ) { @@ -573,10 +572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if self.tcx().try_unify_abstract_consts(( - (a.def, a.substs(self.tcx())), - (b.def, b.substs(self.tcx())), - )) { + if self.tcx().try_unify_abstract_consts((a, b)) { return Ok(EvaluatedToOk); } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 8527852f0dab3..a11d70eac2a7b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -128,8 +128,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(a.into()); wf.compute(b.into()); } - ty::PredicateKind::ConstEvaluatable(def, substs) => { - let obligations = wf.nominal_obligations(def.did, substs); + ty::PredicateKind::ConstEvaluatable(uv) => { + let substs = uv.substs(wf.tcx()); + let obligations = wf.nominal_obligations(uv.def.did, substs); wf.out.extend(obligations); for arg in substs.iter() { @@ -438,8 +439,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(uv.def, substs) - .to_predicate(self.tcx()); + let predicate = ty::PredicateKind::ConstEvaluatable( + ty::Unevaluated::new(uv.def, substs), + ) + .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( cause, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3a0b24ae61296..530ff6e460c97 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -531,10 +531,10 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable( + ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, - ) + )) .to_predicate(tcx), )); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 46c610636e31f..d39c17e87312f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2304,11 +2304,8 @@ fn const_evaluatable_predicates_of<'tcx>( if let ty::ConstKind::Unevaluated(uv) = ct.val { assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); - self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs(self.tcx)) - .to_predicate(self.tcx), - span, - )); + self.preds + .insert((ty::PredicateKind::ConstEvaluatable(uv).to_predicate(self.tcx), span)); } } From ddae395583ccad7cfacf1ee8e7bfeb5fca200c90 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Jul 2021 14:05:13 +0200 Subject: [PATCH 52/52] ignore const substs in `implicit_infer` --- compiler/rustc_middle/src/ty/walk.rs | 31 +++++++++++++------ .../src/outlives/implicit_infer.rs | 7 ++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 3cab813f12ad0..73985cf31e0f9 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -11,7 +11,7 @@ use smallvec::{self, SmallVec}; type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { - tcx: TyCtxt<'tcx>, + expose_default_const_substs: Option>, stack: TypeWalkerStack<'tcx>, last_subtree: usize, pub visited: SsoHashSet>, @@ -26,8 +26,13 @@ pub struct TypeWalker<'tcx> { /// It maintains a set of visited types and /// skips any types that are already there. impl<'tcx> TypeWalker<'tcx> { - fn new(tcx: TyCtxt<'tcx>, root: GenericArg<'tcx>) -> Self { - Self { tcx, stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } + fn new(expose_default_const_substs: Option>, root: GenericArg<'tcx>) -> Self { + Self { + expose_default_const_substs, + stack: smallvec![root], + last_subtree: 1, + visited: SsoHashSet::new(), + } } /// Skips the subtree corresponding to the last type @@ -56,7 +61,7 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { let next = self.stack.pop()?; self.last_subtree = self.stack.len(); if self.visited.insert(next) { - push_inner(self.tcx, &mut self.stack, next); + push_inner(self.expose_default_const_substs, &mut self.stack, next); debug!("next: stack={:?}", self.stack); return Some(next); } @@ -76,7 +81,7 @@ impl GenericArg<'tcx> { /// [isize] => { [isize], isize } /// ``` pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { - TypeWalker::new(tcx, self) + TypeWalker::new(Some(tcx), self) } /// Iterator that walks the immediate children of `self`. Hence @@ -92,13 +97,17 @@ impl GenericArg<'tcx> { visited: &mut SsoHashSet>, ) -> impl Iterator> { let mut stack = SmallVec::new(); - push_inner(tcx, &mut stack, self); + push_inner(Some(tcx), &mut stack, self); stack.retain(|a| visited.insert(*a)); stack.into_iter() } } impl<'tcx> super::TyS<'tcx> { + pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> { + TypeWalker::new(None, self.into()) + } + /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types /// that appear in `self`, it does not descend into the fields of @@ -110,7 +119,7 @@ impl<'tcx> super::TyS<'tcx> { /// [isize] => { [isize], isize } /// ``` pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { - TypeWalker::new(tcx, self.into()) + TypeWalker::new(Some(tcx), self.into()) } } @@ -121,7 +130,7 @@ impl<'tcx> super::TyS<'tcx> { /// natural order one would expect (basically, the order of the /// types as they are written). fn push_inner<'tcx>( - tcx: TyCtxt<'tcx>, + expose_default_const_substs: Option>, stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>, ) { @@ -202,7 +211,11 @@ fn push_inner<'tcx>( | ty::ConstKind::Error(_) => {} ty::ConstKind::Unevaluated(ct) => { - stack.extend(ct.substs(tcx).iter().rev()); + if let Some(tcx) = expose_default_const_substs { + stack.extend(ct.substs(tcx).iter().rev()); + } else if let Some(substs) = ct.substs_ { + stack.extend(substs.iter().rev()); + } } } } diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 1c7f88c0bb611..f3f22cb05670c 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -114,7 +114,12 @@ fn insert_required_predicates_to_be_wf<'tcx>( required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for arg in field_ty.walk(tcx) { + // We must not look into the default substs of consts + // as computing those depends on the results of `predicates_of`. + // + // Luckily the only types contained in default substs are type + // parameters which don't matter here. + for arg in field_ty.walk_ignoring_default_const_substs() { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty,