diff options
Diffstat (limited to 'compiler')
214 files changed, 1929 insertions, 2508 deletions
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs index 739c6fd0a43..96277950cfe 100644 --- a/compiler/rustc_apfloat/src/ieee.rs +++ b/compiler/rustc_apfloat/src/ieee.rs @@ -389,7 +389,6 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> { let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize); // Change the exponent from 2^e to 10^e. - #[allow(clippy::comparison_chain)] if exp == 0 { // Nothing to do. } else if exp > 0 { @@ -2527,7 +2526,6 @@ mod sig { if *a_sign ^ b_sign { let (reverse, loss); - #[allow(clippy::comparison_chain)] if bits == 0 { reverse = cmp(a_sig, b_sig) == Ordering::Less; loss = Loss::ExactlyZero; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 5f17008bdc2..927d7c6aaf6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -62,7 +62,7 @@ impl NestedMetaItem { self.meta_item().and_then(|meta_item| meta_item.ident()) } pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::invalid).name + self.ident().unwrap_or_else(Ident::empty).name } /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a @@ -131,7 +131,7 @@ impl Attribute { } } pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::invalid).name + self.ident().unwrap_or_else(Ident::empty).name } pub fn value_str(&self) -> Option<Symbol> { @@ -166,7 +166,7 @@ impl MetaItem { if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } } pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::invalid).name + self.ident().unwrap_or_else(Ident::empty).name } // Example: diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index ba86036577a..f673ab2f3ef 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1060,7 +1060,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) { let item_vis = Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; let item = P(Item { - ident: Ident::invalid(), + ident: Ident::empty(), attrs, id: DUMMY_NODE_ID, vis: item_vis, diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 078dd4bd6e6..500c97e65ef 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -357,13 +357,13 @@ impl ExprPrecedence { } } -/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`. +/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`. pub fn prec_let_scrutinee_needs_par() -> usize { AssocOp::LAnd.precedence() } /// Suppose we have `let _ = e` and the `order` of `e`. -/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS? +/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS? /// /// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`. /// Can we print this as `let _ = a OP b`? diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index f4859ee4ae9..7989af24d99 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -14,6 +14,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } +rustc_query_system = { path = "../rustc_query_system" } rustc_span = { path = "../rustc_span" } rustc_errors = { path = "../rustc_errors" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6027027428e..405e9035c4c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -252,9 +252,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Merge attributes into the inner expression. if !e.attrs.is_empty() { - let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]); + let old_attrs = + self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]); self.attrs.insert( - ex.hir_id, + ex.hir_id.local_id, &*self.arena.alloc_from_iter( e.attrs .iter() @@ -1331,15 +1332,11 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::Expr<'hir> { - let orig_head_span = head.span; // expand <head> - let mut head = self.lower_expr_mut(head); - let desugared_span = self.mark_span_with_reason( - DesugaringKind::ForLoop(ForLoopLoc::Head), - orig_head_span, - None, - ); - head.span = self.lower_span(desugared_span); + let head = self.lower_expr_mut(head); + let desugared_span = + self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None); + let e_span = self.lower_span(e.span); let iter = Ident::with_dummy_span(sym::iter); @@ -1353,23 +1350,24 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::option::Option::Some(val) => __next = val` let pat_arm = { let val_ident = Ident::with_dummy_span(sym::val); - let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident); - let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid); - let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid); + let pat_span = self.lower_span(pat.span); + let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident); + let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid); + let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid); let assign = self.arena.alloc(self.expr( - pat.span, - hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)), + pat_span, + hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)), ThinVec::new(), )); - let some_pat = self.pat_some(pat.span, val_pat); + let some_pat = self.pat_some(pat_span, val_pat); self.arm(some_pat, assign) }; // `::std::option::Option::None => break` let break_arm = { let break_expr = - self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new())); - let pat = self.pat_none(e.span); + self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new())); + let pat = self.pat_none(e_span); self.arm(pat, break_expr) }; @@ -1415,10 +1413,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); let body_expr = self.expr_block(body_block, ThinVec::new()); - let body_stmt = self.stmt_expr(body.span, body_expr); + let body_stmt = self.stmt_expr(body_block.span, body_expr); let loop_block = self.block_all( - e.span, + e_span, arena_vec![self; next_let, match_stmt, pat_let, body_stmt], None, ); @@ -1428,7 +1426,7 @@ impl<'hir> LoweringContext<'_, 'hir> { loop_block, self.lower_label(opt_label), hir::LoopSource::ForLoop, - self.lower_span(e.span.with_hi(orig_head_span.hi())), + self.lower_span(e_span.with_hi(head.span.hi())), ); let loop_expr = self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), @@ -1441,7 +1439,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let into_iter_span = self.mark_span_with_reason( DesugaringKind::ForLoop(ForLoopLoc::IntoIter), - orig_head_span, + head.span, None, ); @@ -1457,7 +1455,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // #82462: to correctly diagnose borrow errors, the block that contains // the iter expr needs to have a span that covers the loop body. let desugared_full_span = - self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None); + self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None); let match_expr = self.arena.alloc(self.expr_match( desugared_full_span, diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_ast_lowering/src/index.rs index efebf73224f..dc2b1a730fb 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -1,44 +1,33 @@ -use crate::arena::Arena; -use crate::hir::map::Map; -use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::definitions; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; -use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; use std::iter::repeat; +use tracing::debug; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { - arena: &'hir Arena<'hir>, - - /// The crate - krate: &'hir Crate<'hir>, - /// Source map source_map: &'a SourceMap, + bodies: &'a IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>, - map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, - parenting: FxHashMap<LocalDefId, HirId>, + /// Outputs + nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, + parenting: FxHashMap<LocalDefId, ItemLocalId>, /// The parent of this node - parent_node: hir::HirId, + parent_node: hir::ItemLocalId, - current_dep_node_owner: LocalDefId, + owner: LocalDefId, definitions: &'a definitions::Definitions, - - hcx: StableHashingContext<'a>, } fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) { @@ -51,137 +40,82 @@ fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V map[k] = Some(v); } -fn hash_body( - hcx: &mut StableHashingContext<'_>, - item_like: impl for<'a> HashStable<StableHashingContext<'a>>, -) -> Fingerprint { - let mut stable_hasher = StableHasher::new(); - hcx.while_hashing_hir_bodies(true, |hcx| { - item_like.hash_stable(hcx, &mut stable_hasher); - }); - stable_hasher.finish() +pub(super) fn index_hir<'hir>( + sess: &Session, + definitions: &definitions::Definitions, + item: hir::OwnerNode<'hir>, + bodies: &IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>, +) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) { + let mut nodes = IndexVec::new(); + // This node's parent should never be accessed: the owner's parent is computed by the + // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is + // used. + nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() })); + let mut collector = NodeCollector { + source_map: sess.source_map(), + definitions, + owner: item.def_id(), + parent_node: ItemLocalId::new(0), + nodes, + bodies, + parenting: FxHashMap::default(), + }; + + match item { + OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID), + OwnerNode::Item(item) => collector.visit_item(item), + OwnerNode::TraitItem(item) => collector.visit_trait_item(item), + OwnerNode::ImplItem(item) => collector.visit_impl_item(item), + OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item), + }; + + (collector.nodes, collector.parenting) } impl<'a, 'hir> NodeCollector<'a, 'hir> { - pub(super) fn root( - sess: &'a Session, - arena: &'hir Arena<'hir>, - krate: &'hir Crate<'hir>, - definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a>, - ) -> NodeCollector<'a, 'hir> { - let mut collector = NodeCollector { - arena, - krate, - source_map: sess.source_map(), - parent_node: hir::CRATE_HIR_ID, - current_dep_node_owner: CRATE_DEF_ID, - definitions, - hcx, - map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()), - parenting: FxHashMap::default(), - }; - collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module())); - - collector - } - - pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> { - // Insert bodies into the map - for (id, body) in self.krate.bodies.iter() { - let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies; - assert!(bodies.insert(id.hir_id.local_id, body).is_none()); - } - IndexedHir { map: self.map, parenting: self.parenting } - } - - fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) { - let hash = hash_body(&mut self.hcx, node); - - let mut nodes = IndexVec::new(); - nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); - - debug_assert!(self.map[owner].is_none()); - self.map[owner] = - Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() })); - } - fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { - debug_assert_eq!(self.current_dep_node_owner, hir_id.owner); + debug_assert_eq!(self.owner, hir_id.owner); debug_assert_ne!(hir_id.local_id.as_u32(), 0); // Make sure that the DepNode of some node coincides with the HirId // owner of that node. if cfg!(debug_assertions) { - if hir_id.owner != self.current_dep_node_owner { - let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), - None => format!("{:?}", node), - }; - - span_bug!( - span, - "inconsistent DepNode at `{:?}` for `{}`: \ + if hir_id.owner != self.owner { + panic!( + "inconsistent DepNode at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_diagnostic_string(span), - node_str, - self.definitions - .def_path(self.current_dep_node_owner) - .to_string_no_crate_verbose(), - self.current_dep_node_owner, + node, + self.definitions.def_path(self.owner).to_string_no_crate_verbose(), + self.owner, self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), hir_id.owner, ) } } - let nodes = self.map[hir_id.owner].as_mut().unwrap(); - - debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner); insert_vec_map( - &mut nodes.nodes, + &mut self.nodes, hir_id.local_id, - ParentedNode { parent: self.parent_node.local_id, node: node }, + ParentedNode { parent: self.parent_node, node: node }, ); } fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) { + debug_assert_eq!(parent_node_id.owner, self.owner); let parent_node = self.parent_node; - self.parent_node = parent_node_id; + self.parent_node = parent_node_id.local_id; f(self); self.parent_node = parent_node; } - fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) { - let prev_owner = self.current_dep_node_owner; - let prev_parent = self.parent_node; - - self.current_dep_node_owner = dep_node_owner; - self.parent_node = HirId::make_owner(dep_node_owner); - f(self); - self.current_dep_node_owner = prev_owner; - self.parent_node = prev_parent; - } - fn insert_nested(&mut self, item: LocalDefId) { - #[cfg(debug_assertions)] - { - let dk_parent = self.definitions.def_key(item).parent.unwrap(); - let dk_parent = LocalDefId { local_def_index: dk_parent }; - let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); - debug_assert_eq!( - dk_parent.owner, self.parent_node.owner, - "Different parents for {:?}", - item - ) - } - - assert_eq!(self.parenting.insert(item, self.parent_node), None); + self.parenting.insert(item, self.parent_node); } } impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - type Map = Map<'hir>; + type Map = !; /// Because we want to track parent items and so forth, enable /// deep walking so that we walk nested items in the context of @@ -194,26 +128,24 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); self.insert_nested(item.def_id); - self.visit_item(self.krate.item(item)); } fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { self.insert_nested(item_id.def_id); - self.visit_trait_item(self.krate.trait_item(item_id)); } fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { self.insert_nested(item_id.def_id); - self.visit_impl_item(self.krate.impl_item(item_id)); } fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { self.insert_nested(foreign_id.def_id); - self.visit_foreign_item(self.krate.foreign_item(foreign_id)); } fn visit_nested_body(&mut self, id: BodyId) { - self.visit_body(self.krate.body(id)); + debug_assert_eq!(id.hir_id.owner, self.owner); + let body = self.bodies[id.hir_id.local_id].unwrap(); + self.visit_body(body); } fn visit_param(&mut self, param: &'hir Param<'hir>) { @@ -226,8 +158,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_item(&mut self, i: &'hir Item<'hir>) { debug!("visit_item: {:?}", i); - self.insert_owner(i.def_id, OwnerNode::Item(i)); - self.with_dep_node_owner(i.def_id, |this| { + debug_assert_eq!(i.def_id, self.owner); + self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(ref struct_def, _) = i.kind { // If this is a tuple or unit-like struct, register the constructor. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { @@ -239,8 +171,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { - self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi)); - self.with_dep_node_owner(fi.def_id, |this| { + debug_assert_eq!(fi.def_id, self.owner); + self.with_parent(fi.hir_id(), |this| { intravisit::walk_foreign_item(this, fi); }); } @@ -257,15 +189,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti)); - self.with_dep_node_owner(ti.def_id, |this| { + debug_assert_eq!(ti.def_id, self.owner); + self.with_parent(ti.hir_id(), |this| { intravisit::walk_trait_item(this, ti); }); } fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii)); - self.with_dep_node_owner(ii.def_id, |this| { + debug_assert_eq!(ii.def_id, self.owner); + self.with_parent(ii.hir_id(), |this| { intravisit::walk_impl_item(this, ii); }); } @@ -353,7 +285,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { s: Span, id: HirId, ) { - assert_eq!(self.parent_node, id); + assert_eq!(self.owner, id.owner); + assert_eq!(self.parent_node, id.local_id); intravisit::walk_fn(self, fk, fd, b, s, id); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a5a4de81f12..e8747f2c5f8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -10,6 +10,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; +use rustc_index::vec::Idx; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -99,11 +100,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> T { let old_len = self.in_scope_lifetimes.len(); - let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind { - hir::ItemKind::Impl(hir::Impl { ref generics, .. }) - | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, - _ => &[], - }; + let parent_generics = + match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind { + hir::ItemKind::Impl(hir::Impl { ref generics, .. }) + | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, + _ => &[], + }; let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind { hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()), _ => None, @@ -493,7 +495,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = hir::ItemKind::Use(path, hir::UseKind::Single); let vis = this.rebuild_vis(&vis); if let Some(attrs) = attrs { - this.attrs.insert(hir::HirId::make_owner(new_id), attrs); + this.attrs.insert(hir::ItemLocalId::new(0), attrs); } let item = hir::Item { @@ -568,7 +570,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs); if let Some(attrs) = attrs { - this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs); + this.attrs.insert(hir::ItemLocalId::new(0), attrs); } let item = hir::Item { @@ -971,7 +973,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::BodyId { let body = hir::Body { generator_kind: self.generator_kind, params, value }; let id = body.id(); - self.bodies.insert(id, body); + debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); + self.bodies.ensure_contains_elem(id.hir_id.local_id, || None); + self.bodies[id.hir_id.local_id] = Some(self.arena.alloc(body)); id } @@ -1124,7 +1128,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // If this is the simple case, this parameter will end up being the same as the // original parameter, but with a different pattern id. - let stmt_attrs = this.attrs.get(¶meter.hir_id).copied(); + let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied(); let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); let new_parameter = hir::Param { hir_id: parameter.hir_id, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 245199e3751..92e08da7a97 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -33,16 +33,18 @@ #![feature(crate_visibility_modifier)] #![feature(box_patterns)] #![feature(iter_zip)] +#![feature(never_type)] #![recursion_limit = "256"] -use rustc_ast::node_id::NodeMap; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -52,13 +54,14 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; -use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind}; +use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -76,6 +79,7 @@ macro_rules! arena_vec { mod asm; mod block; mod expr; +mod index; mod item; mod pat; mod path; @@ -97,13 +101,14 @@ struct LoweringContext<'a, 'hir: 'a> { arena: &'hir Arena<'hir>, /// The items being lowered are collected here. - owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>, - bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>, + owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>, + /// Bodies inside the owner being lowered. + bodies: IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'hir>>>, + /// Attributes inside the owner being lowered. + attrs: BTreeMap<hir::ItemLocalId, &'hir [Attribute]>, generator_kind: Option<hir::GeneratorKind>, - attrs: BTreeMap<hir::HirId, &'hir [Attribute]>, - /// When inside an `async` context, this is the `HirId` of the /// `task_context` local bound to the resume argument of the generator. task_context: Option<hir::HirId>, @@ -152,6 +157,9 @@ struct LoweringContext<'a, 'hir: 'a> { item_local_id_counter: hir::ItemLocalId, node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>, + /// NodeIds that are lowered inside the current HIR owner. + local_node_ids: Vec<NodeId>, + allow_try_trait: Option<Lrc<[Symbol]>>, allow_gen_future: Option<Lrc<[Symbol]>>, } @@ -178,11 +186,13 @@ pub trait ResolverAstLowering { /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; + fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; + fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; - fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>; + fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>; fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>; @@ -200,37 +210,6 @@ pub trait ResolverAstLowering { ) -> LocalDefId; } -struct LoweringHasher<'a> { - source_map: CachingSourceMapView<'a>, - resolver: &'a dyn ResolverAstLowering, -} - -impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> { - #[inline] - fn hash_spans(&self) -> bool { - true - } - - #[inline] - fn def_span(&self, id: LocalDefId) -> Span { - self.resolver.def_span(id) - } - - #[inline] - fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - self.resolver.def_path_hash(def_id) - } - - #[inline] - fn span_data_to_lines_and_cols( - &mut self, - span: &rustc_span::SpanData, - ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)> - { - self.source_map.span_data_to_lines_and_cols(span) - } -} - /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// and if so, what meaning it has. #[derive(Debug)] @@ -314,13 +293,14 @@ pub fn lower_crate<'a, 'hir>( ) -> &'hir hir::Crate<'hir> { let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); + let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count()); LoweringContext { sess, resolver, nt_to_tokenstream, arena, - owners: IndexVec::default(), - bodies: BTreeMap::new(), + owners, + bodies: IndexVec::new(), attrs: BTreeMap::default(), catch_scope: None, loop_scope: None, @@ -331,6 +311,7 @@ pub fn lower_crate<'a, 'hir>( current_hir_id_owner: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_hir_id: IndexVec::new(), + local_node_ids: Vec::new(), generator_kind: None, task_context: None, current_item: None, @@ -420,13 +401,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Crate(lctx.arena.alloc(module)) }); - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in self.resolver.take_trait_map().into_iter() { - if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) { - let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v.into_boxed_slice()); - } - } + let hir_hash = self.compute_hir_hash(); let mut def_id_to_hir_id = IndexVec::default(); @@ -441,24 +416,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id); - #[cfg(debug_assertions)] - for (&id, attrs) in self.attrs.iter() { - // Verify that we do not store empty slices in the map. - if attrs.is_empty() { - panic!("Stored empty attributes for {:?}", id); - } - } - - let krate = - hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs }; + let krate = hir::Crate { owners: self.owners, hir_hash }; self.arena.alloc(krate) } - fn create_stable_hashing_context(&self) -> LoweringHasher<'_> { - LoweringHasher { - source_map: CachingSourceMapView::new(self.sess.source_map()), - resolver: self.resolver, - } + /// Compute the hash for the HIR of the full crate. + /// This hash will then be part of the crate_hash which is stored in the metadata. + fn compute_hir_hash(&mut self) -> Fingerprint { + let definitions = self.resolver.definitions(); + let mut hir_body_nodes: Vec<_> = self + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let info = info.as_ref()?; + let def_path_hash = definitions.def_path_hash(def_id); + Some((def_path_hash, info)) + }) + .collect(); + hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + + let mut stable_hasher = StableHasher::new(); + let mut hcx = self.resolver.create_stable_hashing_context(); + hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() } fn with_hir_id_owner( @@ -468,25 +448,91 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> LocalDefId { let def_id = self.resolver.local_def_id(owner); - // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); - debug_assert_eq!(_old, None); - + let current_attrs = std::mem::take(&mut self.attrs); + let current_bodies = std::mem::take(&mut self.bodies); + let current_node_ids = std::mem::take(&mut self.local_node_ids); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id); let current_local_counter = std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); + // Always allocate the first `HirId` for the owner itself. + let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); + debug_assert_eq!(_old, None); + self.local_node_ids.push(owner); + let item = f(self); + debug_assert_eq!(def_id, item.def_id()); + let info = self.make_owner_info(item); + self.attrs = current_attrs; + self.bodies = current_bodies; + self.local_node_ids = current_node_ids; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; - let _old = self.owners.insert(def_id, item); + let _old = self.owners.insert(def_id, info); debug_assert!(_old.is_none()); def_id } + fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> { + let attrs = std::mem::take(&mut self.attrs); + let bodies = std::mem::take(&mut self.bodies); + let local_node_ids = std::mem::take(&mut self.local_node_ids); + let trait_map = local_node_ids + .into_iter() + .filter_map(|node_id| { + let hir_id = self.node_id_to_hir_id[node_id]?; + let traits = self.resolver.take_trait_map(node_id)?; + Some((hir_id.local_id, traits.into_boxed_slice())) + }) + .collect(); + + #[cfg(debug_assertions)] + for (&id, attrs) in attrs.iter() { + // Verify that we do not store empty slices in the map. + if attrs.is_empty() { + panic!("Stored empty attributes for {:?}", id); + } + } + + let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); + let (nodes, parenting) = + index::index_hir(self.sess, self.resolver.definitions(), node, &bodies); + let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; + let attrs = { + let mut hcx = self.resolver.create_stable_hashing_context(); + let mut stable_hasher = StableHasher::new(); + attrs.hash_stable(&mut hcx, &mut stable_hasher); + let hash = stable_hasher.finish(); + hir::AttributeMap { map: attrs, hash } + }; + + hir::OwnerInfo { nodes, parenting, attrs, trait_map } + } + + /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate + /// queries which depend on the full HIR tree and those which only depend on the item signature. + fn hash_owner( + &mut self, + node: hir::OwnerNode<'hir>, + bodies: &IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'hir>>>, + ) -> (Fingerprint, Fingerprint) { + let mut hcx = self.resolver.create_stable_hashing_context(); + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let hash_including_bodies = stable_hasher.finish(); + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let hash_without_bodies = stable_hasher.finish(); + (hash_including_bodies, hash_without_bodies) + } + /// This method allocates a new `HirId` for the given `NodeId` and stores it in /// the `LoweringContext`'s `NodeId => HirId` map. /// Take care not to call this method if the resulting `HirId` is then not @@ -501,6 +547,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; self.item_local_id_counter.increment_by(1); + self.local_node_ids.push(ast_node_id); hir::HirId { owner, local_id } }) } @@ -547,7 +594,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_internal_unstable, reason, self.sess.edition(), - self.create_stable_hashing_context(), + self.resolver.create_stable_hashing_context(), ) } @@ -791,9 +838,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if attrs.is_empty() { None } else { + debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); debug_assert!(!ret.is_empty()); - self.attrs.insert(id, ret); + self.attrs.insert(id.local_id, ret); Some(ret) } } @@ -819,9 +867,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) { - if let Some(&a) = self.attrs.get(&target_id) { + debug_assert_eq!(id.owner, self.current_hir_id_owner); + debug_assert_eq!(target_id.owner, self.current_hir_id_owner); + if let Some(&a) = self.attrs.get(&target_id.local_id) { debug_assert!(!a.is_empty()); - self.attrs.insert(id, a); + self.attrs.insert(id.local_id, a); } } @@ -1435,7 +1485,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trace!("registering opaque type with id {:#?}", opaque_ty_id); let opaque_ty_item = hir::Item { def_id: opaque_ty_id, - ident: Ident::invalid(), + ident: Ident::empty(), kind: opaque_ty_item_kind, vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited), span: self.lower_span(opaque_ty_span), @@ -2066,7 +2116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_id = self.next_id(); if let Some(a) = attrs { debug_assert!(!a.is_empty()); - self.attrs.insert(hir_id, a); + self.attrs.insert(hir_id.local_id, a); } let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 968e9fa3e24..793f6504be6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -113,7 +113,7 @@ impl<'a> AstValidator<'a> { if sess.opts.unstable_features.is_nightly_build() { sess.struct_span_err(expr.span, "`let` expressions are not supported here") .note("only supported directly in conditions of `if`- and `while`-expressions") - .note("as well as when nested within `&&` and parenthesis in those conditions") + .note("as well as when nested within `&&` and parentheses in those conditions") .emit(); } else { sess.struct_span_err(expr.span, "expected expression, found statement (`let`)") diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c24882086e1..6d0589b7ba1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1675,7 +1675,7 @@ impl<'a> State<'a> { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) } - // Does `expr` need parenthesis when printed in a condition position? + // Does `expr` need parentheses when printed in a condition position? // // These cases need parens due to the parse error observed in #26461: `if return {}` // parses as the erroneous construct `if (return {})`, not `if (return) {}`. diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 8d7f2b65c5a..719caaabbbf 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -802,7 +802,7 @@ impl IntType { /// Valid repr contents: any of the primitive integral type names (see /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use /// the same discriminant size that the corresponding C enum would or C -/// structure layout, `packed` to remove padding, and `transparent` to elegate representation +/// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// concerns to the only non-ZST field. pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { use ReprAttr::*; diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index ee2ce1d3f74..e30d6c7fca7 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -315,9 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // TEMP = &foo // // so extract `temp`. - let temp = if let Some(temp) = assigned_place.as_local() { - temp - } else { + let Some(temp) = assigned_place.as_local() else { span_bug!( self.body.source_info(start_location).span, "expected 2-phase borrow to assign to a local, not `{:?}`", diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 37398894a20..439c728798d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -11,7 +11,6 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; -use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; @@ -247,6 +246,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_name, partially_str, loop_message ), ); + let sess = self.infcx.tcx.sess; + let ty = used_place.ty(self.body, self.infcx.tcx).ty; + // If we have a `&mut` ref, we need to reborrow. + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { + // If we are in a loop this will be suggested later. + if !is_loop_move { + err.span_suggestion_verbose( + move_span.shrink_to_lo(), + &format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else( + || "the mutable reference".to_string() + ), + ), + "&mut *".to_string(), + Applicability::MachineApplicable, + ); + } + } else if let Ok(snippet) = + sess.source_map().span_to_snippet(move_span) + { + err.span_suggestion( + move_span, + "consider borrowing to avoid moving into the for loop", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } } else { err.span_label( fn_call_span, @@ -315,35 +344,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { in_pattern = true; } } - - if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { - let sess = self.infcx.tcx.sess; - let ty = used_place.ty(self.body, self.infcx.tcx).ty; - // If we have a `&mut` ref, we need to reborrow. - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { - // If we are in a loop this will be suggested later. - if !is_loop_move { - err.span_suggestion_verbose( - move_span.shrink_to_lo(), - &format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *".to_string(), - Applicability::MachineApplicable, - ); - } - } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { - err.span_suggestion( - move_span, - "consider borrowing to avoid moving into the for loop", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); - } - } } use_spans.var_span_label_path_only( diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 855e6850b2e..692c20d7dfe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -5,11 +5,10 @@ use rustc_middle::ty; use rustc_mir_dataflow::move_paths::{ IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, }; -use rustc_span::source_map::DesugaringKind; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; -use crate::diagnostics::UseSpans; +use crate::diagnostics::{FnSelfUseKind, UseSpans}; use crate::prefixes::PrefixSet; use crate::MirBorrowckCtxt; @@ -400,19 +399,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { | ty::Opaque(def_id, _) => def_id, _ => return err, }; - let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id); - let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id); - if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { + let diag_name = self.infcx.tcx.get_diagnostic_name(def_id); + if matches!(diag_name, Some(sym::Option | sym::Result)) + && use_spans.map_or(true, |v| !v.for_closure()) + { err.span_suggestion_verbose( span.shrink_to_hi(), - &format!( - "consider borrowing the `{}`'s content", - if is_option { "Option" } else { "Result" } - ), + &format!("consider borrowing the `{}`'s content", diag_name.unwrap()), ".as_ref()".to_string(), Applicability::MaybeIncorrect, ); - } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) { + } else if let Some(UseSpans::FnSelfUse { + kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. }, + .. + }) = use_spans + { let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { type_known_to_meet_bound_modulo_regions( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 246d2e3208c..d5ff4c6766f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -45,12 +45,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let item_msg; let reason; let mut opt_source = None; - let access_place_desc = self.describe_place(access_place.as_ref()); + let access_place_desc = self.describe_any_place(access_place.as_ref()); debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); match the_place_err { PlaceRef { local, projection: [] } => { - item_msg = format!("`{}`", access_place_desc.unwrap()); + item_msg = access_place_desc; if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); } else { @@ -83,7 +83,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If we deref an immutable ref then the suggestion here doesn't help. return; } else { - item_msg = format!("`{}`", access_place_desc.unwrap()); + item_msg = access_place_desc; if self.is_upvar_field_projection(access_place.as_ref()).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { @@ -96,17 +96,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_for_guard() => { - item_msg = format!("`{}`", access_place_desc.unwrap()); + item_msg = access_place_desc; reason = ", as it is immutable for the pattern guard".to_string(); } PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_to_static() => { if access_place.projection.len() == 1 { - item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); + item_msg = format!("immutable static item {}", access_place_desc); reason = String::new(); } else { - item_msg = format!("`{}`", access_place_desc.unwrap()); + item_msg = access_place_desc; let local_info = &self.body.local_decls[local].local_info; if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); @@ -121,7 +121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && proj_base.is_empty() && !self.upvars.is_empty() { - item_msg = format!("`{}`", access_place_desc.unwrap()); + item_msg = access_place_desc; debug_assert!( self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() ); @@ -147,7 +147,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }); let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); opt_source = Some(source); - if let Some(desc) = access_place_desc { + if let Some(desc) = self.describe_place(access_place.as_ref()) { item_msg = format!("`{}`", desc); reason = match error_access { AccessKind::Mutate => format!(", which is behind {}", pointer_type), diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index b15e55cd667..723b57ed970 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -90,9 +90,7 @@ impl OutlivesSuggestionBuilder { let mut unified_already = FxHashSet::default(); for (fr, outlived) in &self.constraints_to_add { - let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) { - fr_name - } else { + let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else { continue; }; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e6260157d11..08df87e0488 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -7,6 +7,7 @@ #![feature(format_args_capture)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 21c26af8178..22bb3a29425 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -689,6 +689,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { // them down. let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec(); + // Convert to the SCC representative: sometimes we have inference + // variables in the member constraint that wind up equated with + // universal regions. The scc representative is the minimal numbered + // one from the corresponding scc so it will be the universal region + // if one exists. + for c_r in &mut choice_regions { + let scc = self.constraint_sccs.scc(*c_r); + *c_r = self.scc_representatives[scc]; + } + // The 'member region' in a member constraint is part of the // hidden type, which must be in the root universe. Therefore, // it cannot have any placeholders in its value. diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 70c74940d62..f71cf09ecf6 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,20 +1,18 @@ use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::free_regions::FreeRegionRelations; use rustc_infer::infer::outlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; use crate::{ - nll::ToRegionVid, type_check::constraint_conversion, type_check::{Locations, MirTypeckRegionConstraints}, universal_regions::UniversalRegions, @@ -383,21 +381,3 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { } } } - -/// This trait is used by the `impl-trait` constraint code to abstract -/// over the `FreeRegionMap` from lexical regions and -/// `UniversalRegions` (from NLL)`. -impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { - fn sub_free_regions( - &self, - _tcx: TyCtxt<'tcx>, - shorter: ty::Region<'tcx>, - longer: ty::Region<'tcx>, - ) -> bool { - let shorter = shorter.to_region_vid(); - assert!(self.universal_regions.is_universal_region(shorter)); - let longer = longer.to_region_vid(); - assert!(self.universal_regions.is_universal_region(longer)); - self.outlives(longer, shorter) - } -} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7bf119863fd..7e69e710d68 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -36,7 +36,7 @@ use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; +use rustc_trait_selection::opaque_types::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; @@ -185,7 +185,6 @@ pub(crate) fn type_check<'mir, 'tcx>( ®ion_bound_pairs, implicit_region_bound, &mut borrowck_context, - &universal_region_relations, |mut cx| { cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); @@ -253,15 +252,7 @@ pub(crate) fn type_check<'mir, 'tcx>( } #[instrument( - skip( - infcx, - body, - promoted, - region_bound_pairs, - borrowck_context, - universal_region_relations, - extra - ), + skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra), level = "debug" )] fn type_check_internal<'a, 'tcx, R>( @@ -272,7 +263,6 @@ fn type_check_internal<'a, 'tcx, R>( region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, ) -> R { let mut checker = TypeChecker::new( @@ -282,7 +272,6 @@ fn type_check_internal<'a, 'tcx, R>( region_bound_pairs, implicit_region_bound, borrowck_context, - universal_region_relations, ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, body, promoted); @@ -901,7 +890,6 @@ struct TypeChecker<'a, 'tcx> { implicit_region_bound: ty::Region<'tcx>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, } struct BorrowCheckContext<'a, 'tcx> { @@ -1050,7 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, ) -> Self { let mut checker = Self { infcx, @@ -1062,7 +1049,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: Default::default(), - universal_region_relations, }; checker.check_user_type_annotations(); checker @@ -1322,8 +1308,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), )?; - let universal_region_relations = self.universal_region_relations; - // Finally, if we instantiated the anon types successfully, we // have to solve any bounds (e.g., `-> impl Iterator` needs to // prove that `T: Iterator` where `T` is the type we @@ -1335,12 +1319,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::OpaqueType, CustomTypeOp::new( |infcx| { - infcx.constrain_opaque_type( - opaque_type_key, - &opaque_decl, - GenerateMemberConstraints::IfNoStaticBound, - universal_region_relations, - ); + infcx.constrain_opaque_type(opaque_type_key, &opaque_decl); Ok(InferOk { value: (), obligations: vec![] }) }, || "opaque_type_map".to_string(), diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index c032364c008..198287f608e 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -812,7 +812,7 @@ pub fn expand_global_asm<'cx>( Ok(args) => { if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { MacEager::items(smallvec![P(ast::Item { - ident: Ident::invalid(), + ident: Ident::empty(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(inline_asm), diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 241c90c1571..31a35b9b7b4 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -85,7 +85,7 @@ impl MultiItemModifier for Expander { fn dummy_annotatable() -> Annotatable { Annotatable::GenericParam(ast::GenericParam { id: ast::DUMMY_NODE_ID, - ident: Ident::invalid(), + ident: Ident::empty(), attrs: Default::default(), bounds: Default::default(), is_placeholder: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index cd78c016caa..a225b328ab6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -724,7 +724,7 @@ impl<'a> TraitDef<'a> { cx.item( self.span, - Ident::invalid(), + Ident::empty(), a, ast::ItemKind::Impl(Box::new(ast::ImplKind { unsafety, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index bcf95719db5..fa389a51115 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -178,7 +178,7 @@ fn inject_impl_of_structural_trait( let newitem = cx.item( span, - Ident::invalid(), + Ident::empty(), attrs, ItemKind::Impl(Box::new(ImplKind { unsafety: ast::Unsafe::No, diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e0d57267525..e106f6014a3 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -77,7 +77,7 @@ pub fn inject( let use_item = cx.item( span, - Ident::invalid(), + Ident::empty(), vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index d0d492e9674..bc1594d82ec 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,10 +1,10 @@ -#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler, box_syntax)] +#![feature(start, core_intrinsics, alloc_error_handler, box_syntax)] #![no_std] extern crate alloc; extern crate alloc_system; -use alloc::prelude::v1::*; +use alloc::boxed::Box; use alloc_system::System; diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 32cc50eebe4..0a8d6122aa7 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -224,7 +224,7 @@ pub(crate) fn run_aot( tcx, (backend_config.clone(), cgu.name()), module_codegen, - rustc_middle::dep_graph::hash_result, + Some(rustc_middle::dep_graph::hash_result), ); if let Some((id, product)) = work_product { diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index bc6dd007ba0..74ea7ec4ede 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -1,10 +1,10 @@ -#![feature(start, box_syntax, core_intrinsics, alloc_prelude, alloc_error_handler)] +#![feature(start, box_syntax, core_intrinsics, alloc_error_handler)] #![no_std] extern crate alloc; extern crate alloc_system; -use alloc::prelude::v1::*; +use alloc::boxed::Box; use alloc_system::System; diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 9f96096574f..a3b8d328388 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -59,7 +59,13 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); - let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + cgu_name, + module_codegen, + Some(dep_graph::hash_result), + ); let time_to_codegen = start_time.elapsed(); drop(prof_timer); diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index a6a553b31a3..5f3f5334475 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -11,7 +11,7 @@ doctest = false bitflags = "1.0" cstr = "0.2" libc = "0.2" -measureme = "9.1.0" +measureme = "10.0.0" snap = "1" tracing = "0.1" rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 3026c2fa030..8766caef6e3 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -113,8 +113,13 @@ pub fn compile_codegen_unit( let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); - let (module, _) = - tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + cgu_name, + module_codegen, + Some(dep_graph::hash_result), + ); let time_to_codegen = start_time.elapsed(); // We assume that the cost to run LLVM on a CGU is proportional to diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index cf1c6058897..be50911f4e1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -174,9 +174,8 @@ pub fn each_linked_rlib( _ => {} } } - let fmts = match fmts { - Some(f) => f, - None => return Err("could not find formats for rlibs".to_string()), + let Some(fmts) = fmts else { + return Err("could not find formats for rlibs".to_string()); }; for &cnum in crates { match fmts.get(cnum.as_usize() - 1) { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 609316ea69f..accb54e4645 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -480,14 +480,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>( } if let Some(trait_ref) = trait_ref { - push_item_name(tcx, trait_ref.skip_binder().def_id, true, &mut vtable_name); + let trait_ref = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); + push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); - push_generic_params_internal( - tcx, - trait_ref.skip_binder().substs, - &mut vtable_name, - &mut visited, - ); + push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited); } else { vtable_name.push_str("_"); } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index b759e3a7a7a..f78196d7ec5 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -3,6 +3,7 @@ #![feature(box_patterns)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] +#![feature(let_else)] #![feature(once_cell)] #![feature(nll)] #![feature(associated_type_bounds)] diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index ce6cec67ad4..bea55bbc879 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -343,9 +343,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) .ty; - let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self { - (llptr, llextra) - } else { + let OperandValue::Ref(llptr, Some(llextra), _) = self else { bug!("store_unsized called with a sized value") }; diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index df4cc295fac..80551518d3c 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; @@ -44,8 +43,8 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } else { false } - } else if let Some(fn_like) = FnLikeNode::from_node(node) { - if fn_like.constness() == hir::Constness::Const { + } else if let Some(fn_kind) = node.fn_kind() { + if fn_kind.constness() == hir::Constness::Const { return true; } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 202c9cad8eb..8efe3eb868b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -72,9 +72,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); - } else if Some(def_id) == self.tcx.lang_items().panic_fmt() - || Some(def_id) == self.tcx.lang_items().begin_panic_fmt() - { + } else if Some(def_id) == self.tcx.lang_items().panic_fmt() { // For panic_fmt, call const_panic_fmt instead. if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() { return Ok(Some( diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index eb0fdebb665..a16388d5de2 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -35,7 +35,8 @@ where ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { - let unused_params = self.tcx.unused_generic_params(def_id); + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused_params = self.tcx.unused_generic_params(instance); for (index, subst) in substs.into_iter().enumerate() { let index = index .try_into() diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 7ce40b319a1..f308e764e86 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -13,6 +13,7 @@ Rust MIR: a lowered representation of Rust. #![feature(exact_size_is_empty)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(slice_ptr_get)] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index d704c4335c7..03e60deea27 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -22,7 +22,7 @@ use std::mem; use std::ops::Deref; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop}; +use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -39,7 +39,8 @@ type QualifResults<'mir, 'tcx, Q> = #[derive(Default)] pub struct Qualifs<'mir, 'tcx> { has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>, - needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>, + needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>, + needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>, indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>, } @@ -80,14 +81,14 @@ impl Qualifs<'mir, 'tcx> { location: Location, ) -> bool { let ty = ccx.body.local_decls[local].ty; - if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { + if !NeedsDrop::in_any_value_of_ty(ccx, ty) { return false; } let needs_drop = self.needs_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + FlowSensitiveAnalysis::new(NeedsDrop, ccx) .into_engine(tcx, &body) .iterate_to_fixpoint() .into_results_cursor(&body) @@ -97,6 +98,33 @@ impl Qualifs<'mir, 'tcx> { needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) } + /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. + /// + /// Only updates the cursor if absolutely necessary + pub fn needs_non_const_drop( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { + return false; + } + + let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { + let ConstCx { tcx, body, .. } = *ccx; + + FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + .into_engine(tcx, &body) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + needs_non_const_drop.seek_before_primary_effect(location); + needs_non_const_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) + } + /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. /// /// Only updates the cursor if absolutely necessary. @@ -173,6 +201,7 @@ impl Qualifs<'mir, 'tcx> { ConstQualifs { needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), + needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), custom_eq, error_occured, @@ -999,7 +1028,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { } // Forbid all `Drop` terminators unless the place being dropped is a local with no - // projections that cannot be `NeedsDrop`. + // projections that cannot be `NeedsNonConstDrop`. TerminatorKind::Drop { place: dropped_place, .. } | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate @@ -1019,15 +1048,15 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { return; } - let needs_drop = if let Some(local) = dropped_place.as_local() { + let needs_non_const_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_drop(self.ccx, local, location) + self.qualifs.needs_non_const_drop(self.ccx, local, location) } else { true }; - if needs_drop { + if needs_non_const_drop { self.check_op_spanned( ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 0a852282f8f..58d0f1a3ad8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -79,7 +79,6 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { || Some(def_id) == tcx.lang_items().panic_display() || Some(def_id) == tcx.lang_items().begin_panic_fn() || Some(def_id) == tcx.lang_items().panic_fmt() - || Some(def_id) == tcx.lang_items().begin_panic_fmt() } /// Returns `true` if this `DefId` points to one of the lang items that will be handled differently diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index 1a8c8b1c78d..7a2be3c3bad 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -97,7 +97,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { // `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is // initialized with `None` and never changed, it still emits drop glue. // Hence we additionally check the qualifs here to allow more code to pass. - if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) { + if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) { // Use the span where the dropped local was declared for the error. let span = self.body.local_decls[dropped_place.local].source_info.span; self.check_live_drop(span); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 5eb7d7a91cc..5418f6fc007 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -21,7 +21,8 @@ pub fn in_any_value_of_ty( ) -> ConstQualifs { ConstQualifs { has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), - needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), + needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), + needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), custom_eq: CustomEq::in_any_value_of_ty(cx, ty), error_occured, } @@ -98,9 +99,31 @@ impl Qualif for HasMutInterior { } /// Constant containing an ADT that implements `Drop`. -/// This must be ruled out (a) because we cannot run `Drop` during compile-time -/// as that might not be a `const fn`, and (b) because implicit promotion would -/// remove side-effects that occur as part of dropping that value. +/// This must be ruled out because implicit promotion would remove side-effects +/// that occur as part of dropping that value. N.B., the implicit promotion has +/// to reject const Drop implementations because even if side-effects are ruled +/// out through other means, the execution of the drop could diverge. +pub struct NeedsDrop; + +impl Qualif for NeedsDrop { + const ANALYSIS_NAME: &'static str = "flow_needs_drop"; + const IS_CLEARED_ON_MOVE: bool = true; + + fn in_qualifs(qualifs: &ConstQualifs) -> bool { + qualifs.needs_drop + } + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(cx.tcx, cx.param_env) + } + + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { + adt.has_dtor(cx.tcx) + } +} + +/// Constant containing an ADT that implements non-const `Drop`. +/// This must be ruled out because we cannot run `Drop` during compile-time. pub struct NeedsNonConstDrop; impl Qualif for NeedsNonConstDrop { @@ -108,7 +131,7 @@ impl Qualif for NeedsNonConstDrop { const IS_CLEARED_ON_MOVE: bool = true; fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.needs_drop + qualifs.needs_non_const_drop } fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool { @@ -122,9 +145,7 @@ impl Qualif for NeedsNonConstDrop { Ok([..]) => {} } - let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() { - did - } else { + let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else { // there is no way to define a type that needs non-const drop // without having the lang item present. return false; diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 7cfe3d7f809..ebcc8213c60 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -230,7 +230,7 @@ impl<'tcx> Validator<'_, 'tcx> { // We cannot promote things that need dropping, since the promoted value // would not get dropped. - if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) { + if self.qualif_local::<qualifs::NeedsDrop>(place.local) { return Err(Unpromotable); } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 49962570129..e3395df3590 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -23,7 +23,7 @@ rustc-hash = "1.1.0" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" -measureme = "9.1.0" +measureme = "10.0.0" libc = "0.2" stacker = "0.1.14" tempfile = "3.2" diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs index 81e2501ecbe..3c7bea27124 100644 --- a/compiler/rustc_data_structures/src/base_n.rs +++ b/compiler/rustc_data_structures/src/base_n.rs @@ -14,7 +14,7 @@ const BASE_64: &[u8; MAX_BASE as usize] = #[inline] pub fn push_str(mut n: u128, base: usize, output: &mut String) { - debug_assert!((2..=MAX_BASE).contains(&base)); + debug_assert!(base >= 2 && base <= MAX_BASE); let mut s = [0u8; 128]; let mut index = 0; diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 9ff401c3c7a..1aa7ac024d9 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -206,11 +206,17 @@ impl<N: Debug, E: Debug> Graph<N, E> { AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ { + pub fn successor_nodes<'a>( + &'a self, + source: NodeIndex, + ) -> impl Iterator<Item = NodeIndex> + 'a { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ { + pub fn predecessor_nodes<'a>( + &'a self, + target: NodeIndex, + ) -> impl Iterator<Item = NodeIndex> + 'a { self.incoming_edges(target).sources() } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 1c6979dc489..a9db3497b23 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -48,7 +48,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>( let node = frame.node; visited[node] = true; - for successor in frame.iter.by_ref() { + while let Some(successor) = frame.iter.next() { if !visited[successor] { stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }); continue 'recurse; @@ -112,7 +112,7 @@ where /// This is equivalent to just invoke `next` repeatedly until /// you get a `None` result. pub fn complete_search(&mut self) { - for _ in self {} + while let Some(_) = self.next() {} } /// Returns true if node has been visited thus far. diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index caf515b0d19..25b7a84b3a0 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -390,7 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> { .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); - self.compress(|_| unreachable!()); + self.compress(|_| assert!(false)); errors } @@ -612,7 +612,7 @@ impl<O: ForestObligation> ObligationForest<O> { fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { let orig_nodes_len = self.nodes.len(); let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); - assert!(node_rewrites.is_empty()); + debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; @@ -623,13 +623,13 @@ impl<O: ForestObligation> ObligationForest<O> { // self.nodes[0..index - dead_nodes] are the first remaining nodes // self.nodes[index - dead_nodes..index] are all dead // self.nodes[index..] are unchanged - for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() { + for index in 0..orig_nodes_len { let node = &self.nodes[index]; match node.state.get() { NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); - *node_rewrite -= dead_nodes; + node_rewrites[index] -= dead_nodes; } } NodeState::Done => { @@ -646,7 +646,7 @@ impl<O: ForestObligation> ObligationForest<O> { } // Extract the success stories. outcome_cb(&node.obligation); - *node_rewrite = orig_nodes_len; + node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } NodeState::Error => { @@ -655,7 +655,7 @@ impl<O: ForestObligation> ObligationForest<O> { // check against. self.active_cache.remove(&node.obligation.as_cache_key()); self.insert_into_error_cache(index); - *node_rewrite = orig_nodes_len; + node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } NodeState::Success => unreachable!(), diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 0bbd0eda0c6..c21939209fc 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -110,12 +110,14 @@ bitflags::bitflags! { const FUNCTION_ARGS = 1 << 6; const LLVM = 1 << 7; const INCR_RESULT_HASHING = 1 << 8; + const ARTIFACT_SIZES = 1 << 9; const DEFAULT = Self::GENERIC_ACTIVITIES.bits | Self::QUERY_PROVIDERS.bits | Self::QUERY_BLOCKED.bits | Self::INCR_CACHE_LOADS.bits | - Self::INCR_RESULT_HASHING.bits; + Self::INCR_RESULT_HASHING.bits | + Self::ARTIFACT_SIZES.bits; const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits; } @@ -136,6 +138,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ ("args", EventFilter::ARGS), ("llvm", EventFilter::LLVM), ("incr-result-hashing", EventFilter::INCR_RESULT_HASHING), + ("artifact-sizes", EventFilter::ARTIFACT_SIZES), ]; /// Something that uniquely identifies a query invocation. @@ -285,6 +288,33 @@ impl SelfProfilerRef { }) } + /// Record the size of an artifact that the compiler produces + /// + /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.) + /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename) + #[inline(always)] + pub fn artifact_size<A>(&self, artifact_kind: &str, artifact_name: A, size: u64) + where + A: Borrow<str> + Into<String>, + { + drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| { + let builder = EventIdBuilder::new(&profiler.profiler); + let event_label = profiler.get_or_alloc_cached_string(artifact_kind); + let event_arg = profiler.get_or_alloc_cached_string(artifact_name); + let event_id = builder.from_label_and_arg(event_label, event_arg); + let thread_id = get_thread_id(); + + profiler.profiler.record_integer_event( + profiler.artifact_size_event_kind, + event_id, + thread_id, + size, + ); + + TimingGuard::none() + })) + } + #[inline(always)] pub fn generic_activity_with_args( &self, @@ -372,7 +402,7 @@ impl SelfProfilerRef { ) { drop(self.exec(event_filter, |profiler| { let event_id = StringId::new_virtual(query_invocation_id.0); - let thread_id = std::thread::current().id().as_u64().get() as u32; + let thread_id = get_thread_id(); profiler.profiler.record_instant_event( event_kind(profiler), @@ -425,6 +455,7 @@ pub struct SelfProfiler { incremental_result_hashing_event_kind: StringId, query_blocked_event_kind: StringId, query_cache_hit_event_kind: StringId, + artifact_size_event_kind: StringId, } impl SelfProfiler { @@ -447,6 +478,7 @@ impl SelfProfiler { profiler.alloc_string("IncrementalResultHashing"); let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); + let artifact_size_event_kind = profiler.alloc_string("ArtifactSize"); let mut event_filter_mask = EventFilter::empty(); @@ -491,6 +523,7 @@ impl SelfProfiler { incremental_result_hashing_event_kind, query_blocked_event_kind, query_cache_hit_event_kind, + artifact_size_event_kind, }) } @@ -561,7 +594,7 @@ impl<'a> TimingGuard<'a> { event_kind: StringId, event_id: EventId, ) -> TimingGuard<'a> { - let thread_id = std::thread::current().id().as_u64().get() as u32; + let thread_id = get_thread_id(); let raw_profiler = &profiler.profiler; let timing_guard = raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id); @@ -655,6 +688,10 @@ pub fn duration_to_secs_str(dur: std::time::Duration) -> String { format!("{:.3}", dur.as_secs_f64()) } +fn get_thread_id() -> u32 { + std::thread::current().id().as_u64().get() as u32 +} + // Memory reporting cfg_if! { if #[cfg(windows)] { diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index e80db0845a7..20e2a3b9696 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -205,10 +205,10 @@ impl<K: Ord, V> SortedMap<K, V> { R: RangeBounds<K>, { let start = match range.start_bound() { - Bound::Included(k) => match self.lookup_index_for(k) { + Bound::Included(ref k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, - Bound::Excluded(k) => match self.lookup_index_for(k) { + Bound::Excluded(ref k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, @@ -216,11 +216,11 @@ impl<K: Ord, V> SortedMap<K, V> { }; let end = match range.end_bound() { - Bound::Included(k) => match self.lookup_index_for(k) { + Bound::Included(ref k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, - Bound::Excluded(k) => match self.lookup_index_for(k) { + Bound::Excluded(ref k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, Bound::Unbounded => self.data.len(), diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 1395bb16e87..e92db9ea128 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -75,7 +75,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> { + pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> { self.get_by_key_enumerated(key).map(|(_, v)| v) } @@ -84,7 +84,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> { + pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> { let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key); self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| { let (k, v) = &self.items[i]; diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index d4274e99f1c..2de05cd4e56 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -257,7 +257,11 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> { pub fn remove(&mut self, key: &K) -> Option<V> { match self { SsoHashMap::Array(array) => { - array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1) + if let Some(index) = array.iter().position(|(k, _v)| k == key) { + Some(array.swap_remove(index).1) + } else { + None + } } SsoHashMap::Map(map) => map.remove(key), } @@ -268,7 +272,11 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> { pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { match self { SsoHashMap::Array(array) => { - array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index)) + if let Some(index) = array.iter().position(|(k, _v)| k == key) { + Some(array.swap_remove(index)) + } else { + None + } } SsoHashMap::Map(map) => map.remove_entry(key), } @@ -415,14 +423,14 @@ impl<K, V> IntoIterator for SsoHashMap<K, V> { /// adapts Item of array reference iterator to Item of hashmap reference iterator. #[inline(always)] -fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) { +fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) { let (a, b) = pair; (a, b) } /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. #[inline(always)] -fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) { +fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) { let (a, b) = pair; (a, b) } diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index f71522d3714..29baf4e1ddb 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -75,7 +75,7 @@ impl<T> SsoHashSet<T> { /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. #[inline] - pub fn iter(&self) -> impl Iterator<Item = &T> { + pub fn iter(&'a self) -> impl Iterator<Item = &'a T> { self.into_iter() } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 2e992e76227..354f9dd93cc 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -229,14 +229,14 @@ impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize { impl<CTX> HashStable<CTX> for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = self.to_bits(); + let val: u32 = unsafe { ::std::mem::transmute(*self) }; val.hash_stable(ctx, hasher); } } impl<CTX> HashStable<CTX> for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = self.to_bits(); + let val: u64 = unsafe { ::std::mem::transmute(*self) }; val.hash_stable(ctx, hasher); } } diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index ba22c7f9b97..a4964b7aa0c 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,7 +5,6 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. -#[allow(clippy::identity_op)] const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index a3ece655047..a1ffbae8b15 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -34,7 +34,7 @@ impl<T> Steal<T> { #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { let borrow = self.value.borrow(); - if borrow.is_none() { + if let None = &*borrow { panic!("attempted to read from stolen value: {}", std::any::type_name::<T>()); } ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs index 9e605ea2d98..9b07f86846e 100644 --- a/compiler/rustc_data_structures/src/tiny_list.rs +++ b/compiler/rustc_data_structures/src/tiny_list.rs @@ -48,7 +48,7 @@ impl<T: PartialEq> TinyList<T> { #[inline] pub fn contains(&self, data: &T) -> bool { let mut elem = self.head.as_ref(); - while let Some(e) = elem { + while let Some(ref e) = elem { if &e.data == data { return true; } diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs index ce60d40b24b..1cf030d852e 100644 --- a/compiler/rustc_data_structures/src/vec_linked_list.rs +++ b/compiler/rustc_data_structures/src/vec_linked_list.rs @@ -2,8 +2,8 @@ use rustc_index::vec::{Idx, IndexVec}; pub fn iter<Ls>( first: Option<Ls::LinkIndex>, - links: &Ls, -) -> impl Iterator<Item = Ls::LinkIndex> + '_ + links: &'a Ls, +) -> impl Iterator<Item = Ls::LinkIndex> + 'a where Ls: Links, { diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 8e8bea9525d..2e9050dd672 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -59,23 +59,23 @@ where } fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A where - F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A, + F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A, { match *ppmode { PpHirMode::Normal => { let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir().krate()) + f(&annotation, tcx.hir()) } PpHirMode::Identified => { let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir().krate()) + f(&annotation, tcx.hir()) } PpHirMode::Typed => { abort_on_err(tcx.analysis(()), tcx.sess); let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; - tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate())) + tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir())) } } } @@ -443,17 +443,27 @@ pub fn print_after_hir_lowering<'tcx>( format!("{:#?}", krate) } - Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| { + Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| { debug!("pretty printing HIR {:?}", s); let sess = annotation.sess(); let sm = sess.source_map(); - pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann()) + let attrs = |id| hir_map.attrs(id); + pprust_hir::print_crate( + sm, + hir_map.root_module(), + src_name, + src, + &attrs, + annotation.pp_ann(), + ) }), - HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| { - debug!("pretty printing HIR tree"); - format!("{:#?}", krate) - }), + HirTree => { + call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| { + debug!("pretty printing HIR tree"); + format!("{:#?}", hir_map.krate()) + }) + } _ => unreachable!(), }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md index 58ebf43cc98..ad363816e18 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0482.md +++ b/compiler/rustc_error_codes/src/error_codes/E0482.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + A lifetime of a returned value does not outlive the function call. Erroneous code example: -```compile_fail,E0482 +```compile_fail,E0700 fn prefix<'a>( words: impl Iterator<Item = &'a str> ) -> impl Iterator<Item = String> { // error! @@ -41,7 +43,7 @@ fn prefix( A similar lifetime problem might arise when returning closures: -```compile_fail,E0482 +```compile_fail,E0700 fn foo( x: &mut Vec<i32> ) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error! diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 778d58eeadc..849ffa881df 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -449,11 +449,7 @@ pub trait Emitter { span: &mut MultiSpan, children: &mut Vec<SubDiagnostic>, ) { - let source_map = if let Some(ref sm) = source_map { - sm - } else { - return; - }; + let Some(source_map) = source_map else { return }; debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children); self.fix_multispan_in_extern_macros(source_map, span); for child in children.iter_mut() { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 60a48b5a2d9..b6cf332f511 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -8,6 +8,7 @@ #![feature(if_let_guard)] #![feature(format_args_capture)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(nll)] #[macro_use] @@ -341,7 +342,7 @@ impl CodeSuggestion { }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if prev_hi.line == cur_lo.line { + if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line { // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 38c099fa4f5..1b123520961 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -171,7 +171,7 @@ fn get_features( } if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() { - if allowed.iter().find(|&f| name.as_str() == *f).is_none() { + if allowed.iter().all(|f| name.as_str() != *f) { struct_span_err!( span_handler, mi.span(), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1d6703077ac..89dbd64ed81 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -383,7 +383,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Unsafe::No, ModKind::Loaded(krate.items, Inline::Yes, krate.span) ), - ident: Ident::invalid(), + ident: Ident::empty(), id: ast::DUMMY_NODE_ID, vis: ast::Visibility { span: krate.span.shrink_to_lo(), @@ -447,9 +447,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { - let (invoc, ext) = if let Some(invoc) = invocations.pop() { - invoc - } else { + let Some((invoc, ext)) = invocations.pop() else { self.resolve_imports(); if undetermined_invocations.is_empty() { break; @@ -1024,12 +1022,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) } - fn collect_bang( - &mut self, - mac: ast::MacCall, - span: Span, - kind: AstFragmentKind, - ) -> AstFragment { + fn collect_bang(&mut self, mac: ast::MacCall, kind: AstFragmentKind) -> AstFragment { + // cache the macro call span so that it can be + // easily adjusted for incremental compilation + let span = mac.span(); self.collect(kind, InvocationKind::Bang { mac, span }) } @@ -1087,25 +1083,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); Ok((style == MacStmtStyle::Semicolon, mac, attrs.into())) } - StmtKind::Item(ref item) if matches!(item.kind, ItemKind::MacCall(..)) => { - match stmt.kind { - StmtKind::Item(item) => match item.into_inner() { - ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs)) - } - _ => unreachable!(), - }, + StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => { + match item.into_inner() { + ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { + Ok((mac.args.need_semicolon(), mac, attrs)) + } _ => unreachable!(), } } - StmtKind::Semi(ref expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => { - match stmt.kind { - StmtKind::Semi(expr) => match expr.into_inner() { - ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs.into())) - } - _ => unreachable!(), - }, + StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => { + match expr.into_inner() { + ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { + Ok((mac.args.need_semicolon(), mac, attrs.into())) + } _ => unreachable!(), } } @@ -1222,7 +1212,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() + self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner() } else { assign_id!(self, &mut expr.id, || { ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); @@ -1318,7 +1308,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) + self.collect_bang(mac, AstFragmentKind::OptExpr) .make_opt_expr() .map(|expr| expr.into_inner()) } else { @@ -1339,9 +1329,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { - PatKind::MacCall(mac) => { - self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() - } + PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(), _ => unreachable!(), }); } @@ -1360,12 +1348,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_stmts(); } - let span = stmt.span; match self.take_stmt_bang(stmt) { Ok((add_semicolon, mac, attrs)) => { self.check_attributes(&attrs, &mac); - let mut stmts = - self.collect_bang(mac, span, AstFragmentKind::Stmts).make_stmts(); + let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts(); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -1433,12 +1419,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { item.attrs = attrs; item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => { - self.collect_bang(mac, span, AstFragmentKind::Items).make_items() + self.collect_bang(mac, AstFragmentKind::Items).make_items() } _ => unreachable!(), }) } - ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => { + ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => { let (file_path, dir_path, dir_ownership) = match mod_kind { ModKind::Loaded(_, inline, _) => { // Inline `mod foo { ... }`, but we still need to push directories. @@ -1520,7 +1506,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => { item.attrs = attrs; // The crate root is special - don't assign an ID to it. - if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) { + if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) { assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)) } else { noop_flat_map_item(item, self) @@ -1542,9 +1528,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ast::AssocItemKind::MacCall(ref mac) => { self.check_attributes(&item.attrs, &mac); item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::TraitItems) - .make_trait_items(), + ast::AssocItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items() + } _ => unreachable!(), }) } @@ -1567,9 +1553,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ast::AssocItemKind::MacCall(ref mac) => { self.check_attributes(&item.attrs, &mac); item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ImplItems) - .make_impl_items(), + ast::AssocItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items() + } _ => unreachable!(), }) } @@ -1586,9 +1572,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { }; visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { - ast::TyKind::MacCall(mac) => { - self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() - } + ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(), _ => unreachable!(), }); } @@ -1613,9 +1597,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ast::ForeignItemKind::MacCall(ref mac) => { self.check_attributes(&foreign_item.attrs, &mac); foreign_item.and_then(|item| match item.kind { - ast::ForeignItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) - .make_foreign_items(), + ast::ForeignItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items() + } _ => unreachable!(), }) } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 6dfeb047ec9..521ca2135c6 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -4,6 +4,7 @@ #![feature(format_args_capture)] #![feature(if_let_guard)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 363cc72b52c..dedc6c618b9 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -204,7 +204,7 @@ fn parse_tree( pprust::token_to_string(&token), ); sess.span_diagnostic.span_err(token.span, &msg); - TokenTree::MetaVar(token.span, Ident::invalid()) + TokenTree::MetaVar(token.span, Ident::empty()) } // There are no more tokens. Just return the `$` we already have. diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 9ed5c8b8ffb..4663dd80fa8 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -116,10 +116,8 @@ pub(super) fn transcribe<'a>( loop { // Look at the last frame on the stack. - let tree = if let Some(tree) = stack.last_mut().unwrap().next() { - // If it still has a TokenTree we have not looked at yet, use that tree. - tree - } else { + // If it still has a TokenTree we have not looked at yet, use that tree. + let Some(tree) = stack.last_mut().unwrap().next() else { // This else-case never produces a value for `tree` (it `continue`s or `return`s). // Otherwise, if we have just reached the end of a sequence and we can keep repeating, @@ -190,9 +188,7 @@ pub(super) fn transcribe<'a>( LockstepIterSize::Constraint(len, _) => { // We do this to avoid an extra clone above. We know that this is a // sequence already. - let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq { - (sp, seq) - } else { + let mbe::TokenTree::Sequence(sp, seq) = seq else { unreachable!() }; diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 8e78fcbb8db..12b6bc7bbe7 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -23,7 +23,7 @@ pub fn placeholder( } } - let ident = Ident::invalid(); + let ident = Ident::empty(); let attrs = Vec::new(); let vis = vis.unwrap_or(ast::Visibility { span: DUMMY_SP, diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index e69289b71f9..27390fd2e4d 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -512,7 +512,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match *self { LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)), + EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), HtmlStr(ref s) => format!("<{}>", s), } } diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index f07e52e04da..1a34dd04428 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -19,6 +19,7 @@ macro_rules! arena_types { [] attribute: rustc_ast::Attribute, [] block: rustc_hir::Block<$tcx>, [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>, + [] body: rustc_hir::Body<$tcx>, [] generic_arg: rustc_hir::GenericArg<$tcx>, [] generic_args: rustc_hir::GenericArgs<$tcx>, [] generic_bound: rustc_hir::GenericBound<$tcx>, @@ -36,6 +37,7 @@ macro_rules! arena_types { [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, [] local: rustc_hir::Local<$tcx>, [few] mod_: rustc_hir::Mod<$tcx>, + [] owner_info: rustc_hir::OwnerInfo<$tcx>, [] param: rustc_hir::Param<$tcx>, [] pat: rustc_hir::Pat<$tcx>, [] path: rustc_hir::Path<$tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 11d0178e93b..6f25715fbec 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,6 +1,7 @@ use crate::def::{CtorKind, DefKind, Res}; -use crate::def_id::{DefId, CRATE_DEF_ID}; +use crate::def_id::DefId; crate use crate::hir_id::{HirId, ItemLocalId}; +use crate::intravisit::FnKind; use crate::LangItem; use rustc_ast::util::parser::ExprPrecedence; @@ -9,6 +10,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; @@ -121,7 +123,7 @@ impl LifetimeName { match *self { LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Implicit - | LifetimeName::Error => Ident::invalid(), + | LifetimeName::Error => Ident::empty(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), LifetimeName::Param(param_name) => param_name.ident(), @@ -233,7 +235,7 @@ impl<'hir> PathSegment<'hir> { } pub fn invalid() -> Self { - Self::from_ident(Ident::invalid()) + Self::from_ident(Ident::empty()) } pub fn args(&self) -> &GenericArgs<'hir> { @@ -310,7 +312,7 @@ impl GenericArg<'_> { } pub fn is_synthetic(&self) -> bool { - matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::invalid()) + matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty()) } pub fn descr(&self) -> &'static str { @@ -662,49 +664,84 @@ pub struct WhereEqPredicate<'hir> { pub rhs_ty: &'hir Ty<'hir>, } -/// The top-level data structure that stores the entire contents of -/// the crate currently being compiled. -/// -/// For more details, see the [rustc dev guide]. +/// HIR node coupled with its parent's id in the same HIR owner. /// -/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html -#[derive(Debug)] -pub struct Crate<'hir> { - pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>, - pub bodies: BTreeMap<BodyId, Body<'hir>>, - - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>, - - /// Collected attributes from HIR nodes. - pub attrs: BTreeMap<HirId, &'hir [Attribute]>, +/// The parent is trash when the node is a HIR owner. +#[derive(Clone, Debug)] +pub struct ParentedNode<'tcx> { + pub parent: ItemLocalId, + pub node: Node<'tcx>, } -impl Crate<'hir> { - pub fn module(&self) -> &'hir Mod<'hir> { - if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() } - } +/// Attributes owned by a HIR owner. +#[derive(Debug)] +pub struct AttributeMap<'tcx> { + pub map: BTreeMap<ItemLocalId, &'tcx [Attribute]>, + pub hash: Fingerprint, +} - pub fn item(&self, id: ItemId) -> &'hir Item<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_item() - } +impl<'tcx> AttributeMap<'tcx> { + pub const EMPTY: &'static AttributeMap<'static> = + &AttributeMap { map: BTreeMap::new(), hash: Fingerprint::ZERO }; - pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_trait_item() + #[inline] + pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { + self.map.get(&id).copied().unwrap_or(&[]) } +} - pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_impl_item() - } +/// Map of all HIR nodes inside the current owner. +/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node. +/// The HIR tree, including bodies, is pre-hashed. +#[derive(Debug)] +pub struct OwnerNodes<'tcx> { + /// Pre-computed hash of the full HIR. + pub hash_including_bodies: Fingerprint, + /// Pre-computed hash of the item signature, sithout recursing into the body. + pub hash_without_bodies: Fingerprint, + /// Full HIR for the current owner. + // The zeroth node's parent should never be accessed: the owner's parent is computed by the + // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally + // used. + pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, + /// Content of local bodies. + pub bodies: IndexVec<ItemLocalId, Option<&'tcx Body<'tcx>>>, +} + +/// Full information resulting from lowering an AST node. +#[derive(Debug, HashStable_Generic)] +pub struct OwnerInfo<'hir> { + /// Contents of the HIR. + pub nodes: OwnerNodes<'hir>, + /// Map from each nested owner to its parent's local id. + pub parenting: FxHashMap<LocalDefId, ItemLocalId>, + /// Collected attributes of the HIR nodes. + pub attrs: AttributeMap<'hir>, + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>, +} - pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_foreign_item() +impl<'tcx> OwnerInfo<'tcx> { + #[inline] + pub fn node(&self) -> OwnerNode<'tcx> { + use rustc_index::vec::Idx; + let node = self.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; + let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. + node } +} - pub fn body(&self, id: BodyId) -> &Body<'hir> { - &self.bodies[&id] - } +/// The top-level data structure that stores the entire contents of +/// the crate currently being compiled. +/// +/// For more details, see the [rustc dev guide]. +/// +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#[derive(Debug)] +pub struct Crate<'hir> { + pub owners: IndexVec<LocalDefId, Option<OwnerInfo<'hir>>>, + pub hir_hash: Fingerprint, } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -3222,6 +3259,32 @@ impl<'hir> Node<'hir> { _ => None, } } + + pub fn fn_kind(self) -> Option<FnKind<'hir>> { + match self { + Node::Item(i) => match i.kind { + ItemKind::Fn(ref sig, ref generics, _) => { + Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis)) + } + _ => None, + }, + Node::TraitItem(ti) => match ti.kind { + TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => { + Some(FnKind::Method(ti.ident, sig, None)) + } + _ => None, + }, + Node::ImplItem(ii) => match ii.kind { + ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))), + _ => None, + }, + Node::Expr(e) => match e.kind { + ExprKind::Closure(..) => Some(FnKind::Closure), + _ => None, + }, + _ => None, + } + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 0b25ebc27bd..877871f7c3d 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -56,6 +56,10 @@ rustc_index::newtype_index! { pub struct ItemLocalId { .. } } rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId); +impl ItemLocalId { + /// Signal local id which should never be used. + pub const INVALID: ItemLocalId = ItemLocalId::MAX; +} /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`. pub const CRATE_HIR_ID: HirId = HirId { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1ac2625dd47..cff543760f4 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -117,6 +117,14 @@ impl<'a> FnKind<'a> { FnKind::Closure => None, } } + + pub fn constness(self) -> Constness { + self.header().map_or(Constness::NotConst, |header| header.constness) + } + + pub fn asyncness(self) -> IsAsync { + self.header().map_or(IsAsync::NotAsync, |header| header.asyncness) + } } /// An abstract representation of the HIR `rustc_middle::hir::map::Map`. @@ -130,6 +138,28 @@ pub trait Map<'hir> { fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>; } +// Used when no map is actually available, forcing manual implementation of nested visitors. +impl Map<'hir> for ! { + fn find(&self, _: HirId) -> Option<Node<'hir>> { + unreachable!() + } + fn body(&self, _: BodyId) -> &'hir Body<'hir> { + unreachable!() + } + fn item(&self, _: ItemId) -> &'hir Item<'hir> { + unreachable!() + } + fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> { + unreachable!() + } + fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> { + unreachable!() + } + fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> { + unreachable!() + } +} + /// An erased version of `Map<'hir>`, using dynamic dispatch. /// NOTE: This type is effectively only usable with `NestedVisitorMap::None`. pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index f35353dbfb5..97d4123138e 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -292,7 +292,6 @@ language_item_table! { PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; - BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn, GenericRequirement::None; ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index f5ea044e248..93224d388c0 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -2,10 +2,12 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#![feature(const_btree_new)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(once_cell)] #![feature(min_specialization)] +#![feature(never_type)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 9d5ef279dd7..6e7b765a0c4 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, - TraitItemId, Ty, VisibilityKind, + AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, + ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -21,6 +21,7 @@ pub trait HashStableContext: fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F); + fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher); } impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId { @@ -209,3 +210,35 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> { }); } } + +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + // We ignore the `nodes` and `bodies` fields since these refer to information included in + // `hash` which is hashed in the collector and used for the crate hash. + let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = + *self; + hash_including_bodies.hash_stable(hcx, hasher); + } +} + +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + // We ignore the `map` since it refers to information included in `hash` which is hashed in + // the collector and used for the crate hash. + let AttributeMap { hash, map: _ } = *self; + hash.hash_stable(hcx, hasher); + } +} + +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let Crate { owners: _, hir_hash } = self; + hir_hash.hash_stable(hcx, hasher) + } +} + +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitCandidate { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + hcx.hash_hir_trait_candidate(self, hasher) + } +} diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9196344cb3f..9c2927111a6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -15,7 +15,6 @@ use rustc_target::spec::abi::Abi; use std::borrow::Cow; use std::cell::Cell; -use std::collections::BTreeMap; use std::vec; pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String { @@ -69,7 +68,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { pub struct State<'a> { pub s: pp::Printer, comments: Option<Comments<'a>>, - attrs: &'a BTreeMap<hir::HirId, &'a [ast::Attribute]>, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a (dyn PpAnn + 'a), } @@ -146,17 +145,18 @@ pub const INDENT_UNIT: usize = 4; /// it can scan the input text for comments to copy forward. pub fn print_crate<'a>( sm: &'a SourceMap, - krate: &hir::Crate<'_>, + krate: &hir::Mod<'_>, filename: FileName, input: String, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> String { - let mut s = State::new_from_input(sm, filename, input, &krate.attrs, ann); + let mut s = State::new_from_input(sm, filename, input, attrs, ann); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. - s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID)); + s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID)); s.print_remaining_comments(); s.s.eof() } @@ -166,7 +166,7 @@ impl<'a> State<'a> { sm: &'a SourceMap, filename: FileName, input: String, - attrs: &'a BTreeMap<hir::HirId, &[ast::Attribute]>, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> State<'a> { State { @@ -178,7 +178,7 @@ impl<'a> State<'a> { } fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { - self.attrs.get(&id).map_or(&[], |la| *la) + (self.attrs)(id) } } @@ -186,8 +186,7 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String where F: FnOnce(&mut State<'_>), { - let mut printer = - State { s: pp::mk_printer(), comments: None, attrs: &BTreeMap::default(), ann }; + let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann }; f(&mut printer); printer.s.eof() } @@ -1168,7 +1167,7 @@ impl<'a> State<'a> { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals()) } - // Does `expr` need parenthesis when printed in a condition position? + // Does `expr` need parentheses when printed in a condition position? // // These cases need parens due to the parse error observed in #26461: `if return {}` // parses as the erroneous construct `if (return {})`, not `if (return) {}`. diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index d42e2f7a99c..571337a8dcb 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -126,30 +126,36 @@ impl IfThisChanged<'tcx> { if attr.has_name(sym::rustc_if_this_changed) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner), - Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) { - Ok(n) => n, - Err(()) => { - self.tcx.sess.span_fatal( - attr.span, - &format!("unrecognized DepNode variant {:?}", n), - ); + None => { + DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner) + } + Some(n) => { + match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) { + Ok(n) => n, + Err(()) => { + self.tcx.sess.span_fatal( + attr.span, + &format!("unrecognized DepNode variant {:?}", n), + ); + } } - }, + } }; self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node)); } else if attr.has_name(sym::rustc_then_this_would_need) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) { - Ok(n) => n, - Err(()) => { - self.tcx.sess.span_fatal( - attr.span, - &format!("unrecognized DepNode variant {:?}", n), - ); + Some(n) => { + match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) { + Ok(n) => n, + Err(()) => { + self.tcx.sess.span_fatal( + attr.span, + &format!("unrecognized DepNode variant {:?}", n), + ); + } } - }, + } None => { self.tcx.sess.span_fatal(attr.span, "missing DepNode variant"); } diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index f089cbcfca6..dd3f8c937f8 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,6 +2,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] +#![feature(let_else)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 55286384de3..b2eaf61b7d1 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -15,7 +15,7 @@ use rustc_ast::{self as ast, Attribute, NestedMetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::Node as HirNode; @@ -302,18 +302,6 @@ impl DirtyCleanVisitor<'tcx> { out } - fn dep_nodes<'l>( - &self, - labels: &'l Labels, - def_id: DefId, - ) -> impl Iterator<Item = DepNode> + 'l { - let def_path_hash = self.tcx.def_path_hash(def_id); - labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) { - Ok(dep_node) => dep_node, - Err(()) => unreachable!("label: {}", label), - }) - } - fn dep_node_str(&self, dep_node: &DepNode) -> String { if let Some(def_id) = dep_node.extract_def_id(self.tcx) { format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) @@ -345,16 +333,19 @@ impl DirtyCleanVisitor<'tcx> { } fn check_item(&mut self, item_id: LocalDefId, item_span: Span) { + let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() { let assertion = match self.assertion_maybe(item_id, attr) { Some(a) => a, None => continue, }; self.checked_attrs.insert(attr.id); - for dep_node in self.dep_nodes(&assertion.clean, item_id.to_def_id()) { + for label in assertion.clean { + let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_clean(item_span, dep_node); } - for dep_node in self.dep_nodes(&assertion.dirty, item_id.to_def_id()) { + for label in assertion.dirty { + let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_dirty(item_span, dep_node); } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 572a4fc6971..392c5bdc15a 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -95,6 +95,12 @@ where return; } + sess.prof.artifact_size( + &name.replace(' ', "_"), + path_buf.file_name().unwrap().to_string_lossy(), + encoder.position() as u64, + ); + debug!("save: data written to disk successfully"); } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 2ed0539841a..38cbf5314ef 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -241,9 +241,7 @@ pub fn prepare_session_directory( // have already tried before. let source_directory = find_source_directory(&crate_dir, &source_directories_already_tried); - let source_directory = if let Some(dir) = source_directory { - dir - } else { + let Some(source_directory) = source_directory else { // There's nowhere to copy from, we're done debug!( "no source directory found. Continuing with empty session \ @@ -397,15 +395,14 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo // We acquire a shared lock on the lock file of the directory, so that // nobody deletes it out from under us while we are reading from it. let lock_file_path = lock_file_path(source_dir); - let _lock = if let Ok(lock) = flock::Lock::new( + + // not exclusive + let Ok(_lock) = flock::Lock::new( &lock_file_path, false, // don't wait, false, // don't create false, - ) { - // not exclusive - lock - } else { + ) else { // Could not acquire the lock, don't try to copy from here return Err(()); }; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 573124c8ec9..67b3cec0a3e 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -990,8 +990,9 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { pub fn insert_all_into_row(&mut self, row: R) { assert!(row.index() < self.num_rows); let (start, end) = self.range(row); - for word in self.words[start..end].iter_mut() { - *word = !0; + let words = &mut self.words[..]; + for index in start..end { + words[index] = !0; } self.clear_excess_bits(row); } @@ -1143,7 +1144,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ { + pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a { self.row(row).into_iter().flat_map(|r| r.iter()) } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 69578e85f27..66399d29998 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -634,15 +634,18 @@ impl<I: Idx, T> IndexVec<I, T> { } #[inline] - pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ { + pub fn drain<'a, R: RangeBounds<usize>>( + &'a mut self, + range: R, + ) -> impl Iterator<Item = T> + 'a { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<R: RangeBounds<usize>>( - &mut self, + pub fn drain_enumerated<'a, R: RangeBounds<usize>>( + &'a mut self, range: R, - ) -> impl Iterator<Item = (I, T)> + '_ { + ) -> impl Iterator<Item = (I, T)> + 'a { self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t)) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 126c25f0c38..2173ff1f9ab 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -386,21 +386,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } - - RegionResolutionError::MemberConstraintFailure { - hidden_ty, - member_region, - span, - } => { - let hidden_ty = self.resolve_vars_if_possible(hidden_ty); - unexpected_hidden_region_diagnostic( - self.tcx, - span, - hidden_ty, - member_region, - ) - .emit(); - } } } } @@ -438,8 +423,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::GenericBoundFailure(..) => true, RegionResolutionError::ConcreteFailure(..) | RegionResolutionError::SubSupConflict(..) - | RegionResolutionError::UpperBoundUniverseConflict(..) - | RegionResolutionError::MemberConstraintFailure { .. } => false, + | RegionResolutionError::UpperBoundUniverseConflict(..) => false, }; let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { @@ -454,7 +438,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), - RegionResolutionError::MemberConstraintFailure { span, .. } => span, }); errors } 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 7fba6a823d7..c6ccd9b60a9 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 @@ -263,9 +263,7 @@ pub fn suggest_new_region_bound( match fn_return.kind { TyKind::OpaqueDef(item_id, _) => { let item = tcx.hir().item(item_id); - let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { - opaque - } else { + let ItemKind::OpaqueTy(opaque) = &item.kind else { return; }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 0efe5a56436..ea9d0eae17e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -46,7 +46,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } } - if let RegionResolutionError::ConcreteFailure(origin, _, _) = error.clone() { + if let RegionResolutionError::ConcreteFailure(origin, _, _) + | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone() + { if let SubregionOrigin::CompareImplTypeObligation { span, item_name, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 8dcdd4b149e..90bc5b3b2fe 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -143,9 +143,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // similar to the asyncness fn in rustc_ty_utils::ty let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id); let node = self.tcx().hir().get(hir_id); - let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?; - - Some(fn_like.asyncness()) + let fn_kind = node.fn_kind()?; + Some(fn_kind.asyncness()) } // Here, we check for the case where the anonymous region diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 5f99a23f86e..167a8893a11 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -53,9 +53,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::RelateObjectBound(span) => { label_or_note(span, "...so that it can be closed over into an object"); } - infer::CallReturn(span) => { - label_or_note(span, "...so that return value is valid for the call"); - } infer::DataBorrowed(ty, span) => { label_or_note( span, @@ -281,23 +278,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::CallReturn(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0482, - "lifetime of return value does not outlive the function call" - ); - note_and_explain_region( - self.tcx, - &mut err, - "the return value is only valid for ", - sup, - "", - None, - ); - err - } infer::DataBorrowed(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 728dc2de370..4814b65e320 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -66,8 +66,6 @@ impl<'tcx> FreeRegionMap<'tcx> { /// follows. If we know that `r_b: 'static`, then this function /// will return true, even though we don't know anything that /// directly relates `r_a` and `r_b`. - /// - /// Also available through the `FreeRegionRelations` trait below. pub fn sub_free_regions( &self, tcx: TyCtxt<'tcx>, @@ -131,27 +129,6 @@ impl<'tcx> FreeRegionMap<'tcx> { } } -/// The NLL region handling code represents free region relations in a -/// slightly different way; this trait allows functions to be abstract -/// over which version is in use. -pub trait FreeRegionRelations<'tcx> { - /// Tests whether `r_a <= r_b`. Both must be free regions or - /// `'static`. - fn sub_free_regions( - &self, - tcx: TyCtxt<'tcx>, - shorter: ty::Region<'tcx>, - longer: ty::Region<'tcx>, - ) -> bool; -} - -impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> { - fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool { - // invoke the "inherent method" - self.sub_free_regions(tcx, r_a, r_b) - } -} - impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> { type Lifted = FreeRegionMap<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 869fd225d51..4c9dcab26b1 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -2,7 +2,6 @@ use crate::infer::region_constraints::Constraint; use crate::infer::region_constraints::GenericKind; -use crate::infer::region_constraints::MemberConstraint; use crate::infer::region_constraints::RegionConstraintData; use crate::infer::region_constraints::VarInfos; use crate::infer::region_constraints::VerifyBound; @@ -20,7 +19,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{Region, RegionVid}; -use rustc_span::Span; use std::fmt; /// This function performs lexical region resolution given a complete @@ -28,13 +26,13 @@ use std::fmt; /// iteration to find region values which satisfy all constraints, /// assuming such values can be found. It returns the final values of /// all the variables as well as a set of errors that must be reported. +#[instrument(level = "debug", skip(region_rels, var_infos, data))] pub fn resolve<'tcx>( region_rels: &RegionRelations<'_, 'tcx>, var_infos: VarInfos, data: RegionConstraintData<'tcx>, mode: RegionckMode, ) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) { - debug!("RegionConstraintData: resolve_regions()"); let mut errors = vec![]; let mut resolver = LexicalResolver { region_rels, var_infos, data }; match mode { @@ -109,11 +107,6 @@ pub enum RegionResolutionError<'tcx> { SubregionOrigin<'tcx>, // cause of the constraint Region<'tcx>, // the placeholder `'b` ), - - /// Indicates a failure of a `MemberConstraint`. These arise during - /// impl trait processing explicitly -- basically, the impl trait's hidden type - /// included some region that it was not supposed to. - MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> }, } struct RegionAndOrigin<'tcx> { @@ -150,12 +143,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let graph = self.construct_graph(); self.expand_givens(&graph); - loop { - self.expansion(&mut var_data); - if !self.enforce_member_constraints(&graph, &mut var_data) { - break; - } - } + self.expansion(&mut var_data); self.collect_errors(&mut var_data, errors); self.collect_var_errors(&var_data, &graph, errors); var_data @@ -233,120 +221,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - /// Enforce all member constraints and return true if anything - /// changed. See `enforce_member_constraint` for more details. - fn enforce_member_constraints( - &self, - graph: &RegionGraph<'tcx>, - var_values: &mut LexicalRegionResolutions<'tcx>, - ) -> bool { - // Note: we don't use the `any` combinator because we don't - // want to stop at the first constraint that makes a change. - let mut any_changed = false; - for member_constraint in &self.data.member_constraints { - any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values); - } - any_changed - } - - /// Enforce a constraint like - /// - /// ``` - /// 'r member of ['c...] - /// ``` - /// - /// We look for all choice regions from the list `'c...` that: - /// - /// (a) are greater than the current value of `'r` (which is a lower bound) - /// - /// and - /// - /// (b) are compatible with the upper bounds of `'r` that we can - /// find by traversing the graph. - /// - /// From that list, we look for a *minimal* option `'c_min`. If we - /// find one, then we can enforce that `'r: 'c_min`. - fn enforce_member_constraint( - &self, - graph: &RegionGraph<'tcx>, - member_constraint: &MemberConstraint<'tcx>, - var_values: &mut LexicalRegionResolutions<'tcx>, - ) -> bool { - debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint); - - // The constraint is some inference variable (`vid`) which - // must be equal to one of the options. - let member_vid = match member_constraint.member_region { - ty::ReVar(vid) => *vid, - _ => return false, - }; - - // The current value of `vid` is a lower bound LB -- i.e., we - // know that `LB <= vid` must be true. - let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) { - VarValue::ErrorValue => return false, - VarValue::Value(r) => r, - }; - - // Find all the "upper bounds" -- that is, each region `b` such that - // `r0 <= b` must hold. - let (member_upper_bounds, ..) = - self.collect_bounding_regions(graph, member_vid, OUTGOING, None); - - // Get an iterator over the *available choice* -- that is, - // each choice region `c` where `lb <= c` and `c <= ub` for all the - // upper bounds `ub`. - debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds); - let mut options = member_constraint.choice_regions.iter().filter(|option| { - self.sub_concrete_regions(member_lower_bound, option) - && member_upper_bounds - .iter() - .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region)) - }); - - // If there is more than one option, we only make a choice if - // there is a single *least* choice -- i.e., some available - // region that is `<=` all the others. - let mut least_choice: ty::Region<'tcx> = match options.next() { - Some(&r) => r, - None => return false, - }; - debug!("enforce_member_constraint: least_choice={:?}", least_choice); - for &option in options { - debug!("enforce_member_constraint: option={:?}", option); - if !self.sub_concrete_regions(least_choice, option) { - if self.sub_concrete_regions(option, least_choice) { - debug!("enforce_member_constraint: new least choice"); - least_choice = option; - } else { - debug!("enforce_member_constraint: no least choice"); - return false; - } - } - } - - // (#72087) Different `ty::Regions` can be known to be equal, for - // example, we know that `'a` and `'static` are equal in a function - // with a parameter of type `&'static &'a ()`. - // - // When we have two equal regions like this `expansion` will use - // `lub_concrete_regions` to pick a canonical representative. The same - // choice is needed here so that we don't end up in a cycle of - // `expansion` changing the region one way and the code here changing - // it back. - let lub = self.lub_concrete_regions(least_choice, member_lower_bound); - debug!( - "enforce_member_constraint: final least choice = {:?}\nlub = {:?}", - least_choice, lub - ); - if lub != member_lower_bound { - *var_values.value_mut(member_vid) = VarValue::Value(least_choice); - true - } else { - false - } - } - fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len()); let mut changes = Vec::new(); @@ -461,6 +335,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } /// True if `a <= b`, but not defined over inference variables. + #[instrument(level = "trace", skip(self))] fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool { let tcx = self.tcx(); let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2); @@ -492,6 +367,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// /// Neither `a` nor `b` may be an inference variable (hence the /// term "concrete regions"). + #[instrument(level = "trace", skip(self))] fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let r = match (a, b) { (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => { @@ -562,13 +438,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// After expansion is complete, go and check upper bounds (i.e., /// cases where the region cannot grow larger than a fixed point) /// and check that they are satisfied. + #[instrument(skip(self, var_data, errors))] fn collect_errors( &self, var_data: &mut LexicalRegionResolutions<'tcx>, errors: &mut Vec<RegionResolutionError<'tcx>>, ) { for (constraint, origin) in &self.data.constraints { - debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin); + debug!(?constraint, ?origin); match *constraint { Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { // Expansion will ensure that these constraints hold. Ignore. @@ -580,7 +457,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } debug!( - "collect_errors: region error at {:?}: \ + "region error at {:?}: \ cannot verify that {:?} <= {:?}", origin, sub, sup ); @@ -606,7 +483,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // collect them later. if !self.sub_concrete_regions(a_region, b_region) { debug!( - "collect_errors: region error at {:?}: \ + "region error at {:?}: \ cannot verify that {:?}={:?} <= {:?}", origin, a_vid, a_region, b_region ); @@ -616,23 +493,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - // Check that all member constraints are satisfied. - for member_constraint in &self.data.member_constraints { - let member_region = var_data.normalize(self.tcx(), member_constraint.member_region); - let choice_regions = member_constraint - .choice_regions - .iter() - .map(|&choice_region| var_data.normalize(self.tcx(), choice_region)); - if !choice_regions.clone().any(|choice_region| member_region == choice_region) { - let span = self.tcx().def_span(member_constraint.opaque_type_def_id); - errors.push(RegionResolutionError::MemberConstraintFailure { - span, - hidden_ty: member_constraint.hidden_ty, - member_region, - }); - } - } - for verify in &self.data.verifys { debug!("collect_errors: verify={:?}", verify); let sub = var_data.normalize(self.tcx(), verify.region); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 18836d5a68e..6b905f67e68 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -417,9 +417,6 @@ pub enum SubregionOrigin<'tcx> { /// (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), - /// Region in return type of invoked fn must enclose call - CallReturn(Span), - /// Comparing the signature and requirements of an impl method against /// the containing trait. CompareImplMethodObligation { @@ -1803,7 +1800,6 @@ impl<'tcx> SubregionOrigin<'tcx> { ReborrowUpvar(a, _) => a, DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, - CallReturn(a) => a, CompareImplMethodObligation { span, .. } => span, CompareImplTypeObligation { span, .. } => span, } diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index ef4ad998f10..98f926e9d76 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -2,10 +2,10 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. -use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::sso::SsoHashSet; -use smallvec::SmallVec; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use smallvec::{smallvec, SmallVec}; #[derive(Debug)] pub enum Component<'tcx> { @@ -47,14 +47,16 @@ pub enum Component<'tcx> { EscapingProjection(Vec<Component<'tcx>>), } -impl<'tcx> TyCtxt<'tcx> { - /// Push onto `out` all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut visited = SsoHashSet::new(); - compute_components(self, ty0, out, &mut visited); - debug!("components({:?}) = {:?}", ty0, out); - } +/// Push onto `out` all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. +pub fn push_outlives_components( + tcx: TyCtxt<'tcx>, + ty0: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, +) { + let mut visited = SsoHashSet::new(); + compute_components(tcx, ty0, out, &mut visited); + debug!("components({:?}) = {:?}", ty0, out); } fn compute_components( diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 4dd5e8ba545..03d6c45a653 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,5 +1,6 @@ //! Various code related to computing outlives relations. +pub mod components; pub mod env; pub mod obligations; pub mod verify; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 437083c68dc..91a22ecc5a9 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -1,5 +1,5 @@ //! Code that handles "type-outlives" constraints like `T: 'a`. This -//! is based on the `push_outlives_components` function defined on the tcx, +//! is based on the `push_outlives_components` function defined in rustc_infer, //! but it adds a bit of heuristics on top, in particular to deal with //! associated types and projections. //! @@ -59,13 +59,13 @@ //! might later infer `?U` to something like `&'b u32`, which would //! imply that `'b: 'a`. +use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; use crate::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; @@ -271,7 +271,7 @@ where assert!(!ty.has_escaping_bound_vars()); let mut components = smallvec![]; - self.tcx.push_outlives_components(ty, &mut components); + push_outlives_components(self.tcx, ty, &mut components); self.components_must_outlive(origin, &components, region); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index a4cfaddeeb9..d0f1ff649d0 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -17,6 +17,7 @@ #![feature(box_patterns)] #![feature(extend_one)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(never_type)] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 30d5613d582..c839f824d1c 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,8 +1,8 @@ use smallvec::smallvec; +use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; use rustc_span::symbol::Ident; @@ -200,7 +200,7 @@ impl Elaborator<'tcx> { let visited = &mut self.visited; let mut components = smallvec![]; - tcx.push_outlives_components(ty_max, &mut components); + push_outlives_components(tcx, ty_max, &mut components); self.stack.extend( components .into_iter() diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bcfa0ef3520..eea32083568 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -838,6 +838,7 @@ pub fn create_global_ctxt<'tcx>( dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), + rustc_query_impl::query_callbacks(arena), crate_name, outputs, ) diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 804dc657f2d..b970c9e4911 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -68,10 +68,11 @@ pub enum EscapeError { impl EscapeError { /// Returns true for actual errors, as opposed to warnings. pub fn is_fatal(&self) -> bool { - !matches!( - self, - EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning - ) + match self { + EscapeError::UnskippedWhitespaceWarning => false, + EscapeError::MultipleSkippedLinesWarning => false, + _ => true, + } } } @@ -329,7 +330,7 @@ where callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning)); } let tail = &tail[first_non_space..]; - if let Some(c) = tail.chars().next() { + if let Some(c) = tail.chars().nth(0) { // For error reporting, we would like the span to contain the character that was not // skipped. The +1 is necessary to account for the leading \ that started the escape. let end = start + first_non_space + c.len_utf8() + 1; diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index d147148ac71..d8883b0e66d 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -134,9 +134,8 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { Applicability::MachineApplicable, ); if self.for_expr_span == expr.span { - let expr_span = expr.span.ctxt().outer_expn_data().call_site; diag.span_suggestion( - receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()), + receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), "or remove `.into_iter()` to iterate by value", String::new(), Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 57c1c8f3ecb..c228ecb03fd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -657,6 +657,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { return; } + // If the method is an impl for an item with docs_hidden, don't doc. + if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl { + let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id()); + let impl_ty = cx.tcx.type_of(parent); + let outerdef = match impl_ty.kind() { + ty::Adt(def, _) => Some(def.did), + ty::Foreign(def_id) => Some(*def_id), + _ => None, + }; + let is_hidden = match outerdef { + Some(id) => cx.tcx.is_doc_hidden(id), + None => false, + }; + if is_hidden { + return; + } + } + let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 48b955e41ac..da1edcf6fe3 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -670,7 +670,7 @@ declare_lint! { /// /// ### Explanation /// - /// The parenthesis are not needed, and should be removed. This is the + /// The parentheses are not needed, and should be removed. This is the /// preferred style for writing these expressions. pub(super) UNUSED_PARENS, Warn, diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 0b1b68d83b7..ebe495872c4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -18,7 +18,6 @@ #include "llvm/Support/Host.h" #include "llvm/Support/Memory.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 87f423fb2d5..6d2e7d25336 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -21,6 +21,11 @@ #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#if LLVM_VERSION_LT(14, 0) +#include "llvm/Support/TargetRegistry.h" +#else +#include "llvm/MC/TargetRegistry.h" +#endif #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index 63bdcea87f8..dba885a27fe 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -24,9 +24,11 @@ fn parse_attributes(field: &syn::Field) -> Attributes { } if meta.path().is_ident("project") { if let Meta::List(list) = meta { - if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() { - attrs.project = meta.path().get_ident().cloned(); - any_attr = true; + if let Some(nested) = list.nested.iter().next() { + if let NestedMeta::Meta(meta) = nested { + attrs.project = meta.path().get_ident().cloned(); + any_attr = true; + } } } } diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index c8959dc86ad..80dcf99da62 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -349,14 +349,14 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> { let field_binding = &info.binding.binding; - let option_ty = option_inner_ty(info.ty); + let option_ty = option_inner_ty(&info.ty); let generated_code = self.generate_non_option_field_code( attr, FieldInfo { vis: info.vis, binding: info.binding, - ty: option_ty.unwrap_or(info.ty), + ty: option_ty.unwrap_or(&info.ty), span: info.span, }, )?; @@ -388,7 +388,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { let formatted_str = self.build_format(&s.value(), attr.span()); match name { "message" => { - if type_matches_path(info.ty, &["rustc_span", "Span"]) { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { quote! { #diag.set_span(*#field_binding); #diag.set_primary_message(#formatted_str); @@ -401,7 +401,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { } } "label" => { - if type_matches_path(info.ty, &["rustc_span", "Span"]) { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { quote! { #diag.span_label(*#field_binding, #formatted_str); } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 644b849a9f8..6cf0dd8b1ad 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -2,6 +2,7 @@ #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(let_else)] #![feature(nll)] #![feature(once_cell)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c54ea610602..bbd30c9327a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -529,6 +529,15 @@ impl<'a> CrateLocator<'a> { let mut err_data: Option<Vec<PathBuf>> = None; for (lib, kind) in m { info!("{} reading metadata from: {}", flavor, lib.display()); + if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) { + // Empty files will cause get_metadata_section to fail. Rmeta + // files can be empty, for example with binaries (which can + // often appear with `cargo check` when checking a library as + // a unittest). We don't want to emit a user-visible warning + // in this case as it is not a real problem. + debug!("skipping empty file"); + continue; + } let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) { Ok(blob) => { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 89bb5797a82..ca9daa49aa2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -472,9 +472,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { let len = BytePos::decode(decoder)?; let hi = lo + len; - let sess = if let Some(sess) = decoder.sess { - sess - } else { + let Some(sess) = decoder.sess else { bug!("Cannot decode Span without Session.") }; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4e7f85d2c37..e12f049a90b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -83,6 +83,12 @@ impl IntoArgs for (CrateNum, DefId) { } } +impl IntoArgs for ty::InstanceDef<'tcx> { + fn into_args(self) -> (DefId, DefId) { + (self.def_id(), self.def_id()) + } +} + provide! { <'tcx> tcx, def_id, other, cdata, type_of => { cdata.get_type(def_id.index, tcx) } generics_of => { cdata.get_generics(def_id.index, tcx.sess) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dacb1e4029c..20f7b059b56 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1319,7 +1319,9 @@ impl EncodeContext<'a, 'tcx> { } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); - let unused = self.tcx.unused_generic_params(def_id); + let instance = + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); + let unused = self.tcx.unused_generic_params(instance); if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d06c593d394..daeccde6024 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -12,6 +12,7 @@ bitflags = "1.2.1" either = "1.5.0" gsgdt = "0.1.2" tracing = "0.1" +rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 962aea448b8..420c500a7de 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,12 +92,6 @@ macro_rules! arena_types { [] tys: rustc_middle::ty::TyS<$tcx>, [] predicates: rustc_middle::ty::PredicateInner<$tcx>, - // HIR query types - [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, - [few] hir_definitions: rustc_hir::definitions::Definitions, - [] hir_owner: rustc_middle::hir::Owner<$tcx>, - [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, - // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) @@ -106,6 +100,8 @@ macro_rules! arena_types { // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. [decode] span: rustc_span::Span, [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, + + [] dep_kind: rustc_middle::dep_graph::DepKindStruct, ], $tcx); ) } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 23d475a5953..f3100010770 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -75,145 +75,71 @@ pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual /// jump table instead of large matches. pub struct DepKindStruct { - /// Whether the DepNode has parameters (query keys). - pub(super) has_params: bool, - /// Anonymous queries cannot be replayed from one compiler invocation to the next. /// When their result is needed, it is recomputed. They are useful for fine-grained /// dependency tracking, and caching within one compiler invocation. - pub(super) is_anon: bool, + pub is_anon: bool, /// Eval-always queries do not track their dependencies, and are always recomputed, even if /// their inputs have not changed since the last compiler invocation. The result is still /// cached within one compiler invocation. - pub(super) is_eval_always: bool, + pub is_eval_always: bool, /// Whether the query key can be recovered from the hashed fingerprint. /// See [DepNodeParams] trait for the behaviour of each key type. - // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style - // can be made a specialized associated const. - fingerprint_style: fn() -> FingerprintStyle, -} - -impl std::ops::Deref for DepKind { - type Target = DepKindStruct; - fn deref(&self) -> &DepKindStruct { - &DEP_KINDS[*self as usize] - } + pub fingerprint_style: FingerprintStyle, + + /// The red/green evaluation system will try to mark a specific DepNode in the + /// dependency graph as green by recursively trying to mark the dependencies of + /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` + /// where we don't know if it is red or green and we therefore actually have + /// to recompute its value in order to find out. Since the only piece of + /// information that we have at that point is the `DepNode` we are trying to + /// re-evaluate, we need some way to re-run a query from just that. This is what + /// `force_from_dep_node()` implements. + /// + /// In the general case, a `DepNode` consists of a `DepKind` and an opaque + /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint + /// is usually constructed by computing a stable hash of the query-key that the + /// `DepNode` corresponds to. Consequently, it is not in general possible to go + /// back from hash to query-key (since hash functions are not reversible). For + /// this reason `force_from_dep_node()` is expected to fail from time to time + /// because we just cannot find out, from the `DepNode` alone, what the + /// corresponding query-key is and therefore cannot re-run the query. + /// + /// The system deals with this case letting `try_mark_green` fail which forces + /// the root query to be re-evaluated. + /// + /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. + /// Fortunately, we can use some contextual information that will allow us to + /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we + /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a + /// valid `DefPathHash`. Since we also always build a huge table that maps every + /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have + /// everything we need to re-run the query. + /// + /// Take the `mir_promoted` query as an example. Like many other queries, it + /// just has a single parameter: the `DefId` of the item it will compute the + /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` + /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` + /// is actually a `DefPathHash`, and can therefore just look up the corresponding + /// `DefId` in `tcx.def_path_hash_to_def_id`. + pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>, + + /// Invoke a query to put the on-disk cached value in memory. + pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>, } impl DepKind { #[inline(always)] - pub fn fingerprint_style(&self) -> FingerprintStyle { + pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle { // Only fetch the DepKindStruct once. - let data: &DepKindStruct = &**self; + let data = tcx.query_kind(self); if data.is_anon { return FingerprintStyle::Opaque; } - - (data.fingerprint_style)() - } -} - -// erase!() just makes tokens go away. It's used to specify which macro argument -// is repeated (i.e., which sub-expression of the macro we are in) but don't need -// to actually use any of the arguments. -macro_rules! erase { - ($x:tt) => {{}}; -} - -macro_rules! is_anon_attr { - (anon) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! is_eval_always_attr { - (eval_always) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! contains_anon_attr { - ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false}); -} - -macro_rules! contains_eval_always_attr { - ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false}); -} - -#[allow(non_upper_case_globals)] -pub mod dep_kind { - use super::*; - use crate::ty::query::query_keys; - use rustc_query_system::dep_graph::FingerprintStyle; - - // We use this for most things when incr. comp. is turned off. - pub const Null: DepKindStruct = DepKindStruct { - has_params: false, - is_anon: false, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Unit, - }; - - pub const TraitSelect: DepKindStruct = DepKindStruct { - has_params: false, - is_anon: true, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Unit, - }; - - pub const CompileCodegenUnit: DepKindStruct = DepKindStruct { - has_params: true, - is_anon: false, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Opaque, - }; - - pub const CompileMonoItem: DepKindStruct = DepKindStruct { - has_params: true, - is_anon: false, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Opaque, - }; - - macro_rules! define_query_dep_kinds { - ($( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)*) => ( - $(pub const $variant: DepKindStruct = { - const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false; - const is_anon: bool = contains_anon_attr!($($attrs)*); - const is_eval_always: bool = contains_eval_always_attr!($($attrs)*); - - #[inline(always)] - fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle { - <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>> - ::fingerprint_style() - } - - DepKindStruct { - has_params, - is_anon, - is_eval_always, - fingerprint_style, - } - };)* - ); + data.fingerprint_style } - - rustc_dep_node_append!([define_query_dep_kinds!][]); } macro_rules! define_dep_nodes { @@ -225,12 +151,10 @@ macro_rules! define_dep_nodes { ) => ( #[macro_export] macro_rules! make_dep_kind_array { - ($mod:ident) => {[ $(($mod::$variant),)* ]}; + ($mod:ident) => {[ $($mod::$variant()),* ]}; } - static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind); - - /// This enum serves as an index into the `DEP_KINDS` array. + /// This enum serves as an index into arrays built by `make_dep_kind_array`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[allow(non_camel_case_types)] pub enum DepKind { @@ -296,7 +220,7 @@ pub trait DepNodeExt: Sized { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self; /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: @@ -311,7 +235,11 @@ pub trait DepNodeExt: Sized { fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>; /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>; + fn from_label_string( + tcx: TyCtxt<'_>, + label: &str, + def_path_hash: DefPathHash, + ) -> Result<Self, ()>; /// Used in testing fn has_label_string(label: &str) -> bool; @@ -321,8 +249,8 @@ impl DepNodeExt for DepNode { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash); + fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode { + debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } @@ -337,31 +265,27 @@ impl DepNodeExt for DepNode { /// refers to something from the previous compilation session that /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> { - if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash { - Some( - tcx.on_disk_cache - .as_ref()? - .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())), - ) + if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash { + Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))) } else { None } } /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> { + fn from_label_string( + tcx: TyCtxt<'_>, + label: &str, + def_path_hash: DefPathHash, + ) -> Result<DepNode, ()> { let kind = dep_kind_from_label_string(label)?; - match kind.fingerprint_style() { + match kind.fingerprint_style(tcx) { FingerprintStyle::Opaque => Err(()), - FingerprintStyle::Unit => { - if !kind.has_params { - Ok(DepNode::new_no_params(kind)) - } else { - Err(()) - } + FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), + FingerprintStyle::DefPathHash => { + Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) } - FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)), } } @@ -377,10 +301,12 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { FingerprintStyle::Unit } + #[inline(always)] fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { Fingerprint::ZERO } + #[inline(always)] fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { Some(()) } @@ -392,14 +318,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { tcx.def_path_hash(*self).0 } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { tcx.def_path_str(*self) } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx) } @@ -411,14 +340,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { self.to_def_id().to_fingerprint(tcx) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { self.to_def_id().to_debug_str(tcx) } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx).map(|id| id.expect_local()) } @@ -430,15 +362,18 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; def_id.to_fingerprint(tcx) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { tcx.crate_name(*self).to_string() } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx).map(|id| id.krate) } @@ -453,6 +388,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let (def_id_0, def_id_1) = *self; @@ -462,6 +398,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { def_path_hash_0.0.combine(def_path_hash_1.0) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { let (def_id_0, def_id_1) = *self; @@ -478,6 +415,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index cda99639074..79d7ca32f35 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -12,7 +12,7 @@ pub use rustc_query_system::dep_graph::{ SerializedDepNodeIndex, WorkProduct, WorkProductId, }; -pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt}; crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; @@ -24,29 +24,8 @@ pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; - #[inline(always)] - fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle { - DepKind::fingerprint_style(self) - } - - #[inline(always)] - fn is_eval_always(&self) -> bool { - self.is_eval_always - } - - #[inline(always)] - fn has_params(&self) -> bool { - self.has_params - } - fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", node.kind)?; - - if !node.kind.has_params && !node.kind.is_anon { - return Ok(()); - } - - write!(f, "(")?; + write!(f, "{:?}(", node.kind)?; ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { @@ -110,4 +89,51 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { fn sess(&self) -> &Session { self.sess } + + #[inline(always)] + fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle { + kind.fingerprint_style(*self) + } + + #[inline(always)] + fn is_eval_always(&self, kind: DepKind) -> bool { + self.query_kind(kind).is_eval_always + } + + fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool { + debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); + + // We must avoid ever having to call `force_from_dep_node()` for a + // `DepNode::codegen_unit`: + // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we + // would always end up having to evaluate the first caller of the + // `codegen_unit` query that *is* reconstructible. This might very well be + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just + // to re-trigger calling the `codegen_unit` query with the right key. At + // that point we would already have re-done all the work we are trying to + // avoid doing in the first place. + // The solution is simple: Just explicitly call the `codegen_unit` query for + // each CGU, right after partitioning. This way `try_mark_green` will always + // hit the cache instead of having to go through `force_from_dep_node`. + // This assertion makes sure, we actually keep applying the solution above. + debug_assert!( + dep_node.kind != DepKind::codegen_unit, + "calling force_from_dep_node() on DepKind::codegen_unit" + ); + + let cb = self.query_kind(dep_node.kind); + if let Some(f) = cb.force_from_dep_node { + f(*self, dep_node); + true + } else { + false + } + } + + fn try_load_from_on_disk_cache(&self, dep_node: DepNode) { + let cb = self.query_kind(dep_node.kind); + if let Some(f) = cb.try_load_from_on_disk_cache { + f(*self, dep_node) + } + } } diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs deleted file mode 100644 index 8efec8ef567..00000000000 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! This module provides a simplified abstraction for working with -//! code blocks identified by their integer `NodeId`. In particular, -//! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, -//! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e., the code -//! that is run when the function-like thing it represents is invoked. -//! -//! With the above abstraction in place, one can treat the program -//! text as a collection of blocks of code (and most such blocks are -//! nested within a uniquely determined `FnLike`), and users can ask -//! for the `Code` associated with a particular NodeId. - -use crate::hir::map::Map; -use rustc_hir as hir; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{Expr, FnDecl, Node}; -use rustc_span::symbol::Ident; -use rustc_span::Span; - -/// An FnLikeNode is a Node that is like a fn, in that it has a decl -/// and a body (as well as a NodeId, a span, etc). -/// -/// More specifically, it is one of either: -/// -/// - A function item, -/// - A closure expr (i.e., an ExprKind::Closure), or -/// - The default implementation for a trait method. -/// -/// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone, Debug)] -pub struct FnLikeNode<'a> { - node: Node<'a>, -} - -/// MaybeFnLike wraps a method that indicates if an object -/// corresponds to some FnLikeNode. -trait MaybeFnLike { - fn is_fn_like(&self) -> bool; -} - -impl MaybeFnLike for hir::Item<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::ImplItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ImplItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::TraitItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) - } -} - -impl MaybeFnLike for hir::Expr<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ExprKind::Closure(..)) - } -} - -/// Carries either an FnLikeNode or an Expr, as these are the two -/// constructs that correspond to "code" (as in, something from which -/// we can construct a control-flow graph). -#[derive(Copy, Clone)] -pub enum Code<'a> { - FnLike(FnLikeNode<'a>), - Expr(&'a Expr<'a>), -} - -impl<'a> Code<'a> { - pub fn id(&self) -> hir::HirId { - match *self { - Code::FnLike(node) => node.id(), - Code::Expr(block) => block.hir_id, - } - } - - /// Attempts to construct a Code from presumed FnLike or Expr node input. - pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> { - match map.get(id) { - Node::Block(_) => { - // Use the parent, hopefully an expression node. - Code::from_node(map, map.get_parent_node(id)) - } - Node::Expr(expr) => Some(Code::Expr(expr)), - node => FnLikeNode::from_node(node).map(Code::FnLike), - } - } -} - -/// These are all the components one can extract from a fn item for -/// use when implementing FnLikeNode operations. -struct ItemFnParts<'a> { - ident: Ident, - decl: &'a hir::FnDecl<'a>, - header: hir::FnHeader, - vis: &'a hir::Visibility<'a>, - generics: &'a hir::Generics<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -/// These are all the components one can extract from a closure expr -/// for use when implementing FnLikeNode operations. -struct ClosureParts<'a> { - decl: &'a FnDecl<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self { - ClosureParts { decl: d, body: b, id, span: s } - } -} - -impl<'a> FnLikeNode<'a> { - /// Attempts to construct a FnLikeNode from presumed FnLike node input. - pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> { - let fn_like = match node { - Node::Item(item) => item.is_fn_like(), - Node::TraitItem(tm) => tm.is_fn_like(), - Node::ImplItem(it) => it.is_fn_like(), - Node::Expr(e) => e.is_fn_like(), - _ => false, - }; - fn_like.then_some(FnLikeNode { node }) - } - - pub fn body(self) -> hir::BodyId { - self.handle( - |i: ItemFnParts<'a>| i.body, - |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body, - |c: ClosureParts<'a>| c.body, - ) - } - - pub fn decl(self) -> &'a FnDecl<'a> { - self.handle( - |i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl, - |c: ClosureParts<'a>| c.decl, - ) - } - - pub fn span(self) -> Span { - self.handle( - |i: ItemFnParts<'_>| i.span, - |_, _, _: &'a hir::FnSig<'a>, _, _, span| span, - |c: ClosureParts<'_>| c.span, - ) - } - - pub fn id(self) -> hir::HirId { - self.handle( - |i: ItemFnParts<'_>| i.id, - |id, _, _: &'a hir::FnSig<'a>, _, _, _| id, - |c: ClosureParts<'_>| c.id, - ) - } - - pub fn constness(self) -> hir::Constness { - self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness) - } - - pub fn asyncness(self) -> hir::IsAsync { - self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness) - } - - pub fn unsafety(self) -> hir::Unsafety { - self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety) - } - - pub fn kind(self) -> FnKind<'a> { - let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.ident, p.generics, p.header, p.vis) - }; - let closure = |_: ClosureParts<'a>| FnKind::Closure; - let method = - |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis); - self.handle(item, method, closure) - } - - fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A - where - I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce( - hir::HirId, - Ident, - &'a hir::FnSig<'a>, - Option<&'a hir::Visibility<'a>>, - hir::BodyId, - Span, - ) -> A, - C: FnOnce(ClosureParts<'a>) -> A, - { - match self.node { - Node::Item(i) => match i.kind { - hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts { - id: i.hir_id(), - ident: i.ident, - decl: &sig.decl, - body: block, - vis: &i.vis, - span: i.span, - header: sig.header, - generics, - }), - _ => bug!("item FnLikeNode that is not fn-like"), - }, - Node::TraitItem(ti) => match ti.kind { - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - method(ti.hir_id(), ti.ident, sig, None, body, ti.span) - } - _ => bug!("trait method FnLikeNode that is not fn-like"), - }, - Node::ImplItem(ii) => match ii.kind { - hir::ImplItemKind::Fn(ref sig, body) => { - method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span) - } - _ => bug!("impl method FnLikeNode that is not fn-like"), - }, - Node::Expr(e) => match e.kind { - hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => { - closure(ClosureParts::new(&decl, block, e.hir_id, e.span)) - } - _ => bug!("expr FnLikeNode that is not fn-like"), - }, - _ => bug!("other FnLikeNode that is not fn-like"), - } - } -} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e6f56b0be93..fad7e875fa1 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,4 @@ -use self::collector::NodeCollector; - -use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner}; +use crate::hir::{ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -22,9 +20,6 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::collections::VecDeque; -pub mod blocks; -mod collector; - fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { match node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) @@ -166,8 +161,8 @@ impl<'hir> Map<'hir> { pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir { let krate = self.krate(); - krate.owners.iter().filter_map(|owner| match owner.as_ref()? { - OwnerNode::Item(item) => Some(*item), + krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() { + OwnerNode::Item(item) => Some(item), _ => None, }) } @@ -318,7 +313,7 @@ impl<'hir> Map<'hir> { } pub fn get_parent_node(&self, hir_id: HirId) -> HirId { - self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID) + self.find_parent_node(hir_id).unwrap() } /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. @@ -381,7 +376,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() + self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[id.hir_id.local_id].unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { @@ -443,7 +438,7 @@ impl<'hir> Map<'hir> { pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir { self.body(id).params.iter().map(|arg| match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident, - _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP), + _ => Ident::empty(), }) } @@ -495,11 +490,41 @@ impl<'hir> Map<'hir> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { - self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id)) + self.krate() + .owners + .iter_enumerated() + .flat_map(move |(owner, owner_info)| { + let bodies = &owner_info.as_ref()?.nodes.bodies; + Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| { + if body.is_none() { + return None; + } + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + Some(self.body_owner_def_id(body_id)) + })) + }) + .flatten() } pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) { - par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id))); + use rustc_data_structures::sync::{par_iter, ParallelIterator}; + #[cfg(parallel_compiler)] + use rustc_rayon::iter::IndexedParallelIterator; + + par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { + let owner = LocalDefId::new(owner); + if let Some(owner_info) = owner_info { + par_iter(&owner_info.nodes.bodies.raw).enumerate().for_each(|(local_id, body)| { + if body.is_some() { + let local_id = ItemLocalId::new(local_id); + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + f(self.body_owner_def_id(body_id)) + } + }) + } + }); } pub fn ty_param_owner(&self, id: HirId) -> HirId { @@ -551,9 +576,14 @@ impl<'hir> Map<'hir> { /// Walks the attributes in a crate. pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { let krate = self.krate(); - for (&id, attrs) in krate.attrs.iter() { - for a in *attrs { - visitor.visit_attribute(id, a) + for (owner, info) in krate.owners.iter_enumerated() { + if let Some(info) = info { + for (&local_id, attrs) in info.attrs.map.iter() { + let id = HirId { owner, local_id }; + for a in *attrs { + visitor.visit_attribute(id, a) + } + } } } } @@ -572,7 +602,7 @@ impl<'hir> Map<'hir> { { let krate = self.krate(); for owner in krate.owners.iter().filter_map(Option::as_ref) { - match owner { + match owner.node() { OwnerNode::Item(item) => visitor.visit_item(item), OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), @@ -588,7 +618,7 @@ impl<'hir> Map<'hir> { V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, { let krate = self.krate(); - par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() { + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) { Some(OwnerNode::Item(item)) => visitor.visit_item(item), Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), @@ -839,21 +869,21 @@ impl<'hir> Map<'hir> { pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::Item(item) }) => item, + Some(Owner { node: OwnerNode::Item(item), .. }) => item, _ => bug!("expected item, found {}", self.node_to_string(id)), } } pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ImplItem(item) }) => item, + Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item, _ => bug!("expected impl item, found {}", self.node_to_string(id)), } } pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::TraitItem(item) }) => item, + Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item, _ => bug!("expected trait item, found {}", self.node_to_string(id)), } } @@ -867,7 +897,7 @@ impl<'hir> Map<'hir> { pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ForeignItem(item) }) => item, + Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item, _ => bug!("expected foreign item, found {}", self.node_to_string(id)), } } @@ -1032,42 +1062,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> { - let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map"); - - // We can access untracked state since we are an eval_always query. - let hcx = tcx.create_stable_hashing_context(); - let mut collector = NodeCollector::root( - tcx.sess, - &**tcx.arena, - tcx.untracked_crate, - &tcx.untracked_resolutions.definitions, - hcx, - ); - let top_mod = tcx.untracked_crate.module(); - collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); - - let map = collector.finalize_and_compute_crate_hash(); - tcx.arena.alloc(map) -} - pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - assert_eq!(crate_num, LOCAL_CRATE); - - // We can access untracked state since we are an eval_always query. - let mut hcx = tcx.create_stable_hashing_context(); - - let mut hir_body_nodes: Vec<_> = tcx - .index_hir(()) - .map - .iter_enumerated() - .filter_map(|(def_id, hod)| { - let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id); - let hash = hod.as_ref()?.hash; - Some((def_path_hash, hash, def_id)) - }) - .collect(); - hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + debug_assert_eq!(crate_num, LOCAL_CRATE); + let krate = tcx.hir_crate(()); + let hir_body_hash = krate.hir_hash; let upstream_crates = upstream_crates(tcx); @@ -1087,20 +1085,27 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { source_file_names.sort_unstable(); + let mut hcx = tcx.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); - for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { - def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); - fingerprint.hash_stable(&mut hcx, &mut stable_hasher); - AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id } - .hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.debugging_opts.incremental_relative_spans { - let span = tcx.untracked_resolutions.definitions.def_span(*def_id); - debug_assert_eq!(span.parent(), None); - span.hash_stable(&mut hcx, &mut stable_hasher); - } - } + hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + if tcx.sess.opts.debugging_opts.incremental_relative_spans { + let definitions = &tcx.untracked_resolutions.definitions; + let mut owner_spans: Vec<_> = krate + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let _ = info.as_ref()?; + let def_path_hash = definitions.def_path_hash(def_id); + let span = definitions.def_span(def_id); + debug_assert_eq!(span.parent(), None); + Some((def_path_hash, span)) + }) + .collect(); + owner_spans.sort_unstable_by_key(|bn| bn.0); + owner_spans.hash_stable(&mut hcx, &mut stable_hasher); + } tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 5016c5ce954..95d7273b17b 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -8,28 +8,12 @@ pub mod place; use crate::ty::query::Providers; use crate::ty::TyCtxt; -use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; -use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; -use std::collections::BTreeMap; - -/// Result of HIR indexing. -#[derive(Debug)] -pub struct IndexedHir<'hir> { - /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners. - // The `mut` comes from construction time, and is harmless since we only ever hand out - // immutable refs to IndexedHir. - map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, - /// Map from each owner to its parent's HirId inside another owner. - // This map is separate from `map` to eventually allow for per-owner indexing. - parenting: FxHashMap<LocalDefId, HirId>, -} /// Top-level HIR node for current owner. This only contains the node for which /// `HirId::local_id == 0`, and excludes bodies. @@ -39,85 +23,14 @@ pub struct IndexedHir<'hir> { #[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: OwnerNode<'tcx>, + hash_without_bodies: Fingerprint, } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { node } = self; - hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher)); - } -} - -/// HIR node coupled with its parent's id in the same HIR owner. -/// -/// The parent is trash when the node is a HIR owner. -#[derive(Clone, Debug)] -pub struct ParentedNode<'tcx> { - parent: ItemLocalId, - node: Node<'tcx>, -} - -#[derive(Debug)] -pub struct OwnerNodes<'tcx> { - /// Pre-computed hash of the full HIR. - hash: Fingerprint, - /// Full HIR for the current owner. - // The zeroth node's parent is trash, but is never accessed. - nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, - /// Content of local bodies. - bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>, -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - // We ignore the `nodes` and `bodies` fields since these refer to information included in - // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash, nodes: _, bodies: _ } = *self; - hash.hash_stable(hcx, hasher); - } -} - -/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted -/// to the nodes whose `HirId::owner` is `prefix`. -#[derive(Copy, Clone)] -pub struct AttributeMap<'tcx> { - map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>, - prefix: LocalDefId, -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let range = self.range(); - - range.clone().count().hash_stable(hcx, hasher); - for (key, value) in range { - key.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - } - } -} - -impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("AttributeMap") - .field("prefix", &self.prefix) - .field("range", &&self.range().collect::<Vec<_>>()[..]) - .finish() - } -} - -impl<'tcx> AttributeMap<'tcx> { - fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { - self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[]) - } - - fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> { - let local_zero = ItemLocalId::from_u32(0); - let range = HirId { owner: self.prefix, local_id: local_zero }..HirId { - owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 }, - local_id: local_zero, - }; - self.map.range(range) + let Owner { node: _, hash_without_bodies } = self; + hash_without_bodies.hash_stable(hcx, hasher) } } @@ -149,21 +62,32 @@ pub fn provide(providers: &mut Providers) { hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))) }; providers.hir_crate = |tcx, ()| tcx.untracked_crate; - providers.index_hir = map::index_hir; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; providers.hir_owner = |tcx, id| { - let owner = tcx.index_hir(()).map[id].as_ref()?; - let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; - let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. - Some(Owner { node }) + let owner = tcx.hir_crate(()).owners[id].as_ref()?; + let node = owner.node(); + Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies }) }; - providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref(); + providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { - let index = tcx.index_hir(()); - index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) + // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash. + let parent = tcx.untracked_resolutions.definitions.def_key(id).parent; + let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + let mut parent_hir_id = + tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id); + if let Some(local_id) = + tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id) + { + parent_hir_id.local_id = *local_id; + } + parent_hir_id + }); + parent }; - providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; + providers.hir_attrs = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e41f5add457..0894b805075 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -39,6 +39,7 @@ #![feature(new_uninit)] #![feature(nll)] #![feature(once_cell)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(in_band_lifetimes)] diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b6358f99294..a36c9b6ed73 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -1004,13 +1004,13 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. fn check_init(&self, range: AllocRange) -> AllocResult { - self.is_init(range).or_else(|idx_range| { - Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + self.is_init(range).map_err(|idx_range| { + AllocError::InvalidUninitBytes(Some(UninitBytesAccess { access_offset: range.start, access_size: range.size, uninit_offset: idx_range.start, uninit_size: idx_range.end - idx_range.start, // `Size` subtraction - }))) + })) }) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 67a20d72905..06b42320049 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -47,6 +47,14 @@ pub enum MonoItem<'tcx> { } impl<'tcx> MonoItem<'tcx> { + /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). + pub fn is_user_defined(&self) -> bool { + match *self { + MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, + } + } + pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { MonoItem::Fn(instance) => { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index d5541d7890c..cb3f3850958 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -225,6 +225,7 @@ pub struct BorrowCheckResult<'tcx> { pub struct ConstQualifs { pub has_mut_interior: bool, pub needs_drop: bool, + pub needs_non_const_drop: bool, pub custom_eq: bool, pub error_occured: Option<ErrorReported>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e3eda8483b6..18be9817c5f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -36,18 +36,9 @@ rustc_queries! { /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { eval_always - no_hash desc { "get the crate HIR" } } - /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - /// Avoid calling this query directly. - query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> { - eval_always - no_hash - desc { "index HIR" } - } - /// The items in a module. /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. @@ -62,7 +53,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> { - eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -71,7 +61,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner_parent(key: LocalDefId) -> hir::HirId { - eval_always desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -79,8 +68,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { - eval_always + query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -88,8 +76,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> { - eval_always + query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -933,12 +920,6 @@ rustc_queries! { query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - eval_always } query def_ident_span(def_id: DefId) -> Option<Span> { @@ -1558,11 +1539,11 @@ rustc_queries! { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet<u32> { - cache_on_disk_if { key.is_local() } + query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> { + cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", - tcx.def_path_str(key) + tcx.def_path_str(key.def_id()) } } query backend_optimization_level(_: ()) -> OptLevel { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 83d7c307bdf..8240273acad 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, DepKind, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; @@ -79,11 +79,6 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { 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) -> DefId; - fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>); fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; @@ -1016,6 +1011,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, + query_kinds: &'tcx [DepKindStruct], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>, @@ -1149,6 +1145,7 @@ impl<'tcx> TyCtxt<'tcx> { dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, + query_kinds: &'tcx [DepKindStruct], crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { @@ -1175,6 +1172,7 @@ impl<'tcx> TyCtxt<'tcx> { on_disk_cache, queries, query_caches: query::QueryCaches::default(), + query_kinds, ty_rcache: Default::default(), pred_rcache: Default::default(), selection_cache: Default::default(), @@ -1188,6 +1186,10 @@ impl<'tcx> TyCtxt<'tcx> { } } + crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { + &self.query_kinds[k as usize] + } + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. #[track_caller] pub fn ty_error(self) -> Ty<'tcx> { @@ -1301,6 +1303,27 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// 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 fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId { + debug!("def_path_hash_to_def_id({:?})", hash); + + let stable_crate_id = hash.stable_crate_id(); + + // If this is a DefPathHash from the local crate, we can look up the + // DefId in the tcx's `Definitions`. + if stable_crate_id == self.sess.local_stable_crate_id() { + self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id() + } else { + // If this is a DefPathHash from an upstream crate, let the CrateStore map + // it to a DefId. + let cstore = &self.untracked_resolutions.cstore; + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + cstore.def_path_hash_to_def_id(cnum, hash) + } + } + pub fn def_path_debug_str(self, def_id: DefId) -> String { // We are explicitly not going through queries here in order to get // crate name and stable crate id since this code is called from debug!() @@ -1337,20 +1360,15 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - - StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore) + StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore) } #[inline(always)] pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - StableHashingContext::ignore_spans( self.sess, - krate, &resolutions.definitions, &*resolutions.cstore, ) @@ -2823,7 +2841,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers) { - providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id); + providers.in_scope_traits_map = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map); providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 092eae0fc5c..1b32c8a6698 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -221,9 +221,7 @@ pub fn suggest_constraining_type_param( ) -> bool { let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - let param = if let Some(param) = param { - param - } else { + let Some(param) = param else { return false; }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 08b4d3aecda..bac681bd96f 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -769,11 +769,16 @@ fn foo(&self) -> Self::T { String::new() } ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { - let opaque_local_def_id = def_id.expect_local(); - let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id); - let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind { - hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, - _ => bug!("The HirId comes from a `ty::Opaque`"), + let opaque_local_def_id = def_id.as_local(); + let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { + let hir = self.hir(); + let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id); + match &hir.expect_item(opaque_hir_id).kind { + hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, + _ => bug!("The HirId comes from a `ty::Opaque`"), + } + } else { + return false; }; let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 9b8247fd028..4b38105e447 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -152,6 +152,22 @@ impl<'tcx> InstanceDef<'tcx> { } } + /// Returns the `DefId` of instances which might not require codegen locally. + pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> { + match self { + ty::InstanceDef::Item(def) => Some(def.did), + ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => None, + } + } + #[inline] pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { match self { @@ -567,29 +583,26 @@ impl<'tcx> Instance<'tcx> { return self; } - if let InstanceDef::Item(def) = self.def { - let polymorphized_substs = polymorphize(tcx, def.did, self.substs); - debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); - Self { def: self.def, substs: polymorphized_substs } - } else { - self - } + let polymorphized_substs = polymorphize(tcx, self.def, self.substs); + debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); + Self { def: self.def, substs: polymorphized_substs } } } fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + instance: ty::InstanceDef<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - debug!("polymorphize({:?}, {:?})", def_id, substs); - let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize({:?}, {:?})", instance, substs); + let unused = tcx.unused_generic_params(instance); debug!("polymorphize: unused={:?}", unused); // If this is a closure or generator then we need to handle the case where another closure // from the function is captured as an upvar and hasn't been polymorphized. In this case, // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). + let def_id = instance.def_id(); let upvars_ty = if tcx.is_closure(def_id) { Some(substs.as_closure().tupled_upvars_ty()) } else if tcx.type_of(def_id).is_generator() { @@ -613,7 +626,11 @@ fn polymorphize<'tcx>( debug!("fold_ty: ty={:?}", ty); match ty.kind { ty::Closure(def_id, substs) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { @@ -621,7 +638,11 @@ fn polymorphize<'tcx>( } } ty::Generator(def_id, substs, movability) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d0c7379c2d9..8ec5f4c7978 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -755,17 +755,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Extract the number of elements from the layout of the array field: - let len = if let Ok(TyAndLayout { + let Ok(TyAndLayout { layout: Layout { fields: FieldsShape::Array { count, .. }, .. }, .. - }) = self.layout_of(f0_ty) - { - count - } else { + }) = self.layout_of(f0_ty) else { return Err(LayoutError::Unknown(ty)); }; - (*e_ty, *len, true) + (*e_ty, *count, true) } else { // First ADT field is not an array: (f0_ty, def.non_enum_variant().fields.len() as _, false) @@ -787,9 +784,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Compute the ABI of the element type: let e_ly = self.layout_of(e_ty)?; - let e_abi = if let Abi::Scalar(scalar) = e_ly.abi { - scalar - } else { + let Abi::Scalar(e_abi) = e_ly.abi else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. tcx.sess.fatal(&format!( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0eacedc09ee..20d07bdc48a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -92,7 +92,6 @@ pub mod fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; -pub mod outlives; pub mod print; pub mod query; pub mod relate; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2610a76b281..b11a54d5dcb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -350,18 +350,26 @@ pub trait PrettyPrinter<'tcx>: match self.tcx().extern_crate(def_id) { Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) { (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); - return Ok(( - if !span.is_dummy() { - self.print_def_path(def_id, &[])? - } else { - self.path_crate(cnum)? - }, - true, - )); + // NOTE(eddyb) the only reason `span` might be dummy, + // that we're aware of, is that it's the `std`/`core` + // `extern crate` injected by default. + // FIXME(eddyb) find something better to key this on, + // or avoid ending up with `ExternCrateSource::Extern`, + // for the injected `std`/`core`. + if span.is_dummy() { + return Ok((self.path_crate(cnum)?, true)); + } + + // Disable `try_print_trimmed_def_path` behavior within + // the `print_def_path` call, to avoid infinite recursion + // in cases where the `extern crate foo` has non-trivial + // parents, e.g. it's nested in `impl foo::Trait for Bar` + // (see also issues #55779 and #87932). + self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?; + + return Ok((self, true)); } (ExternCrateSource::Path, LOCAL_CRATE) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); return Ok((self.path_crate(cnum)?, true)); } _ => {} diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index b1bc073ca99..6c1175ebdb4 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -102,6 +102,10 @@ impl TyCtxt<'tcx> { } } +/// Helper for `TyCtxtEnsure` to avoid a closure. +#[inline(always)] +fn noop<T>(_: &T) {} + macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam<DefId> }; ($K:ty) => { $K }; @@ -165,7 +169,7 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { let key = key.into_query_param(); - let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {}); + let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop); let lookup = match cached { Ok(()) => return, @@ -192,9 +196,7 @@ macro_rules! define_callbacks { pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> { let key = key.into_query_param(); - let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| { - value.clone() - }); + let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone); let lookup = match cached { Ok(value) => return value, diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 05995ddcc00..c6a34ece245 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -221,15 +221,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); let closure_span = tcx.hir().span(closure_hir_id); - let (capture_index, capture) = if let Some(capture_details) = + let Some((capture_index, capture)) = find_capture_matching_projections( typeck_results, var_hir_id, closure_def_id, &from_builder.projection, - ) { - capture_details - } else { + ) else { if !enable_precise_capture(tcx, closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b74208edafe..8dadbf5f02b 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -362,11 +362,7 @@ impl DropTree { blocks: &IndexVec<DropIdx, Option<BasicBlock>>, ) { for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() { - let block = if let Some(block) = blocks[drop_idx] { - block - } else { - continue; - }; + let Some(block) = blocks[drop_idx] else { continue }; match drop_data.0.kind { DropKind::Value => { let terminator = TerminatorKind::Drop { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 02023c48a6c..b0f1e08562c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -6,6 +6,7 @@ #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(once_cell)] #![feature(min_specialization)] #![recursion_limit = "256"] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index ef8bd20d510..e4c2d2dce67 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -2,7 +2,6 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::intravisit::FnKind; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; @@ -14,8 +13,8 @@ crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let def_id = body.source.def_id().expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) { - if let FnKind::Closure = fn_like_node.kind() { + if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() { + if let FnKind::Closure = fn_kind { // closures can't recur, so they don't matter. return; } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 402391b87ea..2f3de52965d 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -6,6 +6,7 @@ #![feature(exact_size_is_empty)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(once_cell)] #![feature(stmt_expr_attributes)] diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index c0bf4b659aa..2d27d085b48 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -290,9 +290,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { call: PeekCall, ) { info!(?place, "peek_at"); - let local = if let Some(l) = place.as_local() { - l - } else { + let Some(local) = place.as_local() else { tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); return; }; @@ -312,9 +310,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { call: PeekCall, ) { info!(?place, "peek_at"); - let local = if let Some(l) = place.as_local() { - l - } else { + let Some(local) = place.as_local() else { tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); return; }; diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 17790ec91c8..63c637af5c2 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -68,11 +68,10 @@ impl<'tcx> MirPass<'tcx> for ConstProp { return; } - use rustc_middle::hir::map::blocks::FnLikeNode; let def_id = body.source.def_id().expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst; // Only run const prop on functions, methods, closures and associated constants diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1c946bd2d8a..4ac93f71619 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -14,13 +14,11 @@ use spans::{CoverageSpan, CoverageSpans}; use crate::MirPass; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_index::vec::IndexVec; use rustc_middle::hir; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; use rustc_middle::mir::dump_enabled; @@ -29,7 +27,6 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::ty::TyCtxt; -use rustc_query_system::ich::StableHashingContext; use rustc_span::def_id::DefId; use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; @@ -66,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { } let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local()); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); // Only instrument functions, methods, and closures (not constants since they are evaluated // at compile time by Miri). @@ -76,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { // be tricky if const expressions have no corresponding statements in the enclosing MIR. // Closures are carved out by their initial `Assign` statement.) if !is_fn_like { - trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id()); + trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id()); return; } @@ -574,15 +571,13 @@ fn get_body_span<'tcx>( } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { + // FIXME(cjgillot) Stop hashing HIR manually here. let mut hcx = tcx.create_no_span_stable_hashing_context(); - hash(&mut hcx, &hir_body.value).to_smaller_hash() -} - -fn hash( - hcx: &mut StableHashingContext<'tcx>, - node: &impl HashStable<StableHashingContext<'tcx>>, -) -> Fingerprint { let mut stable_hasher = StableHasher::new(); - node.hash_stable(hcx, &mut stable_hasher); + let owner = hir_body.id().hir_id.owner; + let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies; + hcx.with_hir_bodies(false, owner, bodies, |hcx| { + hir_body.value.hash_stable(hcx, &mut stable_hasher) + }); stable_hasher.finish() } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ee4e91ecb62..84a1e3fb600 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -673,9 +673,7 @@ impl Inliner<'tcx> { assert!(args.next().is_none()); let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() { - s - } else { + let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else { bug!("Closure arguments are not passed as a tuple"); }; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9b11c8f0b24..ab1fe6fe077 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(bootstrap, feature(const_panic))] #![feature(in_band_lifetimes)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(option_get_or_insert_default)] @@ -428,8 +429,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( } let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - use rustc_middle::hir::map::blocks::FnLikeNode; - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); if is_fn_like { let did = def.did.to_def_id(); let def = ty::WithOptConstParam::unknown(did); diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index a2cce9f1eda..822a372d8ce 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -17,9 +17,7 @@ impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let language_items = tcx.lang_items(); - let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() { - slice_len_fn_item - } else { + let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else { // there is no language item to compare to :) return; }; diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 76f0e83c8c3..a04a0b51531 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -208,7 +208,7 @@ fn normalize_array_len_call<'tcx>( operand, cast_ty, ) => { - let local = if let Some(local) = place.as_local() { local } else { return }; + let Some(local) = place.as_local() else { return }; match operand { Operand::Copy(place) | Operand::Move(place) => { let operand_local = @@ -255,9 +255,7 @@ fn normalize_array_len_call<'tcx>( } } Rvalue::Len(place) => { - let local = if let Some(local) = place.local_or_deref_local() { - local - } else { + let Some(local) = place.local_or_deref_local() else { return; }; if let Some(cast_statement_idx) = state.get(&local).copied() { diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 5cef64d7786..2aa50611290 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -83,12 +83,9 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { let bb = BasicBlock::from_usize(bb); trace!("processing block {:?}", bb); - let discriminant_ty = - if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) { - ty - } else { - continue; - }; + let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else { + continue; + }; let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty)); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f06426308a2..5147408210e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -450,7 +450,9 @@ fn collect_items_rec<'tcx>( // involving a dependency, and the lack of context is confusing) in this MVP, we focus on // diagnostics on edges crossing a crate boundary: the collected mono items which are not // defined in the local crate. - if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE + if tcx.sess.diagnostic().err_count() > error_count + && starting_point.node.krate() != LOCAL_CRATE + && starting_point.node.is_user_defined() { let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string()); tcx.sess.span_note_without_error( @@ -934,21 +936,13 @@ fn visit_instance_use<'tcx>( } } -// Returns `true` if we should codegen an instance in the local crate. -// Returns `false` if we can just link to the upstream crate and therefore don't -// need a mono item. +/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we +/// can just link to the upstream crate and therefore don't need a mono item. fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Intrinsic(_) - | ty::InstanceDef::CloneShim(..) => return true, + let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() { + def_id + } else { + return true; }; if tcx.is_foreign_item(def_id) { diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 08b1d7b7fab..f4082153b68 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -2,6 +2,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] +#![feature(let_else)] #![feature(in_band_lifetimes)] #![recursion_limit = "256"] diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 429ed53d379..b41906111b9 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -9,7 +9,7 @@ use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; use super::PartitioningCx; @@ -300,14 +300,21 @@ fn characteristic_def_id_of_mono_item<'tcx>( // call it. return None; } - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); + + // When polymorphization is enabled, methods which do not depend on their generic + // parameters, but the self-type of their impl block do will fail to normalize. + if !tcx.sess.opts.debugging_opts.polymorphize + || !instance.definitely_needs_subst(tcx) + { + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } } } @@ -451,9 +458,7 @@ fn mono_item_visibility( let is_generic = instance.substs.non_erasable_generics().next().is_some(); // Upstream `DefId` instances get different handling than local ones. - let def_id = if let Some(def_id) = def_id.as_local() { - def_id - } else { + let Some(def_id) = def_id.as_local() else { return if export_generics && is_generic { // If it is an upstream monomorphization and we export generics, we must make // it available to downstream crates. diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 0f768b7819b..e6e4438b6d4 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -27,20 +27,23 @@ pub fn provide(providers: &mut Providers) { providers.unused_generic_params = unused_generic_params; } -/// Determine which generic parameters are used by the function/method/closure represented by -/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` -/// indicates all parameters are used). +/// Determine which generic parameters are used by the instance. +/// +/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all +/// parameters are used). #[instrument(level = "debug", skip(tcx))] -fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> { +fn unused_generic_params<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, +) -> FiniteBitSet<u32> { if !tcx.sess.opts.debugging_opts.polymorphize { // If polymorphization disabled, then all parameters are used. return FiniteBitSet::new_empty(); } - // Polymorphization results are stored in cross-crate metadata only when there are unused - // parameters, so assume that non-local items must have only used parameters (else this query - // would not be invoked, and the cross-crate metadata used instead). - if !def_id.is_local() { + let def_id = instance.def_id(); + // Exit early if this instance should not be polymorphized. + if !should_polymorphize(tcx, def_id, instance) { return FiniteBitSet::new_empty(); } @@ -52,41 +55,25 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> { return FiniteBitSet::new_empty(); } - // Exit early when there is no MIR available. - let context = tcx.hir().body_const_context(def_id.expect_local()); - match context { - Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { - debug!("no mir available"); - return FiniteBitSet::new_empty(); - } - Some(_) if !tcx.is_ctfe_mir_available(def_id) => { - debug!("no ctfe mir available"); - return FiniteBitSet::new_empty(); - } - _ => {} - } - // Create a bitset with N rightmost ones for each parameter. let generics_count: u32 = generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); let mut unused_parameters = FiniteBitSet::<u32>::new_empty(); unused_parameters.set_range(0..generics_count); debug!(?unused_parameters, "(start)"); + mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); debug!(?unused_parameters, "(after default)"); // Visit MIR and accumululate used generic parameters. - let body = match context { + let body = match tcx.hir().body_const_context(def_id.expect_local()) { // Const functions are actually called and should thus be considered for polymorphization - // via their runtime MIR + // via their runtime MIR. Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id), Some(_) => tcx.mir_for_ctfe(def_id), }; let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters }; vis.visit_body(body); - debug!(?unused_parameters, "(after visitor)"); - - mark_used_by_predicates(tcx, def_id, &mut unused_parameters); debug!(?unused_parameters, "(end)"); // Emit errors for debugging and testing if enabled. @@ -97,6 +84,49 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> { unused_parameters } +/// Returns `true` if the instance should be polymorphized. +fn should_polymorphize<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + instance: ty::InstanceDef<'tcx>, +) -> bool { + // If an instance's MIR body is not polymorphic then the modified substitutions that are + // derived from polymorphization's result won't make any difference. + if !instance.has_polymorphic_mir_body() { + return false; + } + + // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic. + if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) { + return false; + } + + // Polymorphization results are stored in cross-crate metadata only when there are unused + // parameters, so assume that non-local items must have only used parameters (else this query + // would not be invoked, and the cross-crate metadata used instead). + if !def_id.is_local() { + return false; + } + + // Foreign items have no bodies to analyze. + if tcx.is_foreign_item(def_id) { + return false; + } + + // Make sure there is MIR available. + match tcx.hir().body_const_context(def_id.expect_local()) { + Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { + debug!("no mir available"); + return false; + } + Some(_) if !tcx.is_ctfe_mir_available(def_id) => { + debug!("no ctfe mir available"); + return false; + } + _ => true, + } +} + /// Some parameters are considered used-by-default, such as non-generic parameters and the dummy /// generic parameters from closures, this function marks them as used. `leaf_is_closure` should /// be `true` if the item that `unused_generic_params` was invoked on is a closure. @@ -156,44 +186,6 @@ fn mark_used_by_default_parameters<'tcx>( } } -/// Search the predicates on used generic parameters for any unused generic parameters, and mark -/// those as used. -#[instrument(level = "debug", skip(tcx, def_id))] -fn mark_used_by_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - unused_parameters: &mut FiniteBitSet<u32>, -) { - let def_id = tcx.closure_base_def_id(def_id); - let predicates = tcx.explicit_predicates_of(def_id); - - let mut current_unused_parameters = FiniteBitSet::new_empty(); - // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty - // bit set so that this is skipped if all parameters are already used. - while current_unused_parameters != *unused_parameters { - debug!(?current_unused_parameters, ?unused_parameters); - current_unused_parameters = *unused_parameters; - - for (predicate, _) in predicates.predicates { - // 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 { tcx, unused_parameters }; - predicate.visit_with(&mut vis).is_break() - }; - - if any_param_used { - let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters }; - predicate.visit_with(&mut vis); - } - } - } - - if let Some(parent) = predicates.parent { - mark_used_by_predicates(tcx, parent, unused_parameters); - } -} - /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic /// parameter which was unused. #[instrument(level = "debug", skip(tcx, generics))] @@ -243,7 +235,8 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, generator or constant). #[instrument(level = "debug", skip(self, def_id, substs))] fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { - let unused = self.tcx.unused_generic_params(def_id); + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in substs.iter().enumerate() { let i = i.try_into().unwrap(); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 8095f386fa3..81328e09156 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1342,10 +1342,10 @@ impl<'a> Parser<'a> { self.struct_span_err( MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]), - "unexpected parenthesis surrounding `for` loop head", + "unexpected parentheses surrounding `for` loop head", ) .multipart_suggestion( - "remove parenthesis in `for` loop", + "remove parentheses in `for` loop", vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())], // With e.g. `for (x) in y)` this would replace `(x) in y)` // with `x) in y)` which is syntactically invalid. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 624390a406f..d2167c7a5db 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -216,7 +216,7 @@ impl<'a> Parser<'a> { return Err(e); } - (Ident::invalid(), ItemKind::Use(tree)) + (Ident::empty(), ItemKind::Use(tree)) } else if self.check_fn_front_matter(def_final) { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?; @@ -279,15 +279,15 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Macro) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? - } else if self.is_macro_rules_item() { + } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() { // MACRO_RULES ITEM - self.parse_item_macro_rules(vis)? + self.parse_item_macro_rules(vis, has_bang)? } else if vis.kind.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); } else if macros_allowed && self.check_path() { // MACRO INVOCATION ITEM - (Ident::invalid(), ItemKind::MacCall(self.parse_item_macro(vis)?)) + (Ident::empty(), ItemKind::MacCall(self.parse_item_macro(vis)?)) } else { return Ok(None); }; @@ -300,7 +300,7 @@ impl<'a> Parser<'a> { || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` - || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac` + || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } /// Are we sure this could not possibly be a macro invocation? @@ -586,7 +586,7 @@ impl<'a> Parser<'a> { } }; - Ok((Ident::invalid(), item_kind)) + Ok((Ident::empty(), item_kind)) } fn parse_item_list<T>( @@ -933,7 +933,7 @@ impl<'a> Parser<'a> { let abi = self.parse_abi(); // ABI? let items = self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?; let module = ast::ForeignMod { unsafety, abi, items }; - Ok((Ident::invalid(), ItemKind::ForeignMod(module))) + Ok((Ident::empty(), ItemKind::ForeignMod(module))) } /// Parses a foreign item (one in an `extern { ... }` block). @@ -1534,18 +1534,43 @@ impl<'a> Parser<'a> { Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false }))) } - /// Is this unambiguously the start of a `macro_rules! foo` item definition? - fn is_macro_rules_item(&mut self) -> bool { - self.check_keyword(kw::MacroRules) - && self.look_ahead(1, |t| *t == token::Not) - && self.look_ahead(2, |t| t.is_ident()) + /// Is this a possibly malformed start of a `macro_rules! foo` item definition? + + fn is_macro_rules_item(&mut self) -> IsMacroRulesItem { + if self.check_keyword(kw::MacroRules) { + let macro_rules_span = self.token.span; + + if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) { + return IsMacroRulesItem::Yes { has_bang: true }; + } else if self.look_ahead(1, |t| (t.is_ident())) { + // macro_rules foo + self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`") + .span_suggestion( + macro_rules_span, + "add a `!`", + "macro_rules!".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + + return IsMacroRulesItem::Yes { has_bang: false }; + } + } + + IsMacroRulesItem::No } /// Parses a `macro_rules! foo { ... }` declarative macro. - fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { + fn parse_item_macro_rules( + &mut self, + vis: &Visibility, + has_bang: bool, + ) -> PResult<'a, ItemInfo> { self.expect_keyword(kw::MacroRules)?; // `macro_rules` - self.expect(&token::Not)?; // `!` + if has_bang { + self.expect(&token::Not)?; // `!` + } let ident = self.parse_ident()?; if self.eat(&token::Not) { @@ -2121,3 +2146,8 @@ impl<'a> Parser<'a> { } } } + +enum IsMacroRulesItem { + Yes { has_bang: bool }, + No, +} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5c701fefd17..e50b983ec62 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1258,7 +1258,7 @@ impl<'a> Parser<'a> { /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`, /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. /// If the following element can't be a tuple (i.e., it's a function definition), then - /// it's not a tuple struct field), and the contents within the parentheses isn't valid, + /// it's not a tuple struct field), and the contents within the parentheses aren't valid, /// so emit a proper diagnostic. // Public for rustfmt usage. pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 9ec6effeb4e..01e751ea8b5 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -16,7 +16,7 @@ use rustc_ast::{ }; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym}; @@ -300,6 +300,12 @@ impl<'a> Parser<'a> { None => LocalKind::Decl, Some(init) => { if self.eat_keyword(kw::Else) { + if self.token.is_keyword(kw::If) { + // `let...else if`. Emit the same error that `parse_block()` would, + // but explicitly point out that this pattern is not allowed. + let msg = "conditional `else if` is not supported for `let...else`"; + return Err(self.error_block_no_opening_brace_msg(msg)); + } let els = self.parse_block()?; self.check_let_else_init_bool_expr(&init); self.check_let_else_init_trailing_brace(&init); @@ -328,7 +334,7 @@ impl<'a> Parser<'a> { ), ) .multipart_suggestion( - "wrap the expression in parenthesis", + "wrap the expression in parentheses", suggs, Applicability::MachineApplicable, ) @@ -349,7 +355,7 @@ impl<'a> Parser<'a> { "right curly brace `}` before `else` in a `let...else` statement not allowed", ) .multipart_suggestion( - "try wrapping the expression in parenthesis", + "try wrapping the expression in parentheses", suggs, Applicability::MachineApplicable, ) @@ -392,10 +398,9 @@ impl<'a> Parser<'a> { Ok(block) } - fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { + fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> { let sp = self.token.span; - let tok = super::token_descr(&self.token); - let mut e = self.struct_span_err(sp, &format!("expected `{{`, found {}", tok)); + let mut e = self.struct_span_err(sp, msg); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; // Check to see if the user has written something like @@ -435,7 +440,13 @@ impl<'a> Parser<'a> { _ => {} } e.span_label(sp, "expected `{`"); - Err(e) + e + } + + fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { + let tok = super::token_descr(&self.token); + let msg = format!("expected `{{`, found {}", tok); + Err(self.error_block_no_opening_brace_msg(&msg)) } /// Parses a block. Inner attributes are allowed. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 98400372c36..c4c0c17addf 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -430,7 +430,7 @@ impl<'a> Parser<'a> { } // Parses the `typeof(EXPR)`. - // To avoid ambiguity, the type is surrounded by parenthesis. + // To avoid ambiguity, the type is surrounded by parentheses. fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> { self.expect(&token::OpenDelim(token::Paren))?; let expr = self.parse_anon_const_expr()?; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ae3a9c71c59..4d4e9432e87 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -23,7 +23,7 @@ use rustc_middle::span_bug; use rustc_middle::thir::abstract_const::Node as ACNode; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; @@ -153,11 +153,8 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow<V::BreakTy> { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() { - ACNode::Leaf(leaf) => { - let leaf = leaf.subst(tcx, ct.substs); - self.visit_const(leaf) - } + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) { + ACNode::Leaf(leaf) => self.visit_const(leaf), ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { ControlFlow::CONTINUE diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 89df3d4674b..f984bb1872b 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,9 +7,8 @@ edition = "2021" doctest = false [dependencies] -measureme = "9.0.0" +measureme = "10.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" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index e50a8c191ad..b216d78da94 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -13,13 +13,12 @@ extern crate rustc_macros; #[macro_use] extern crate rustc_middle; -#[macro_use] -extern crate tracing; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::DiagnosticBuilder; -use rustc_middle::dep_graph; +use rustc_middle::arena::Arena; +use rustc_middle::dep_graph::{self, DepKindStruct}; 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}; @@ -29,7 +28,6 @@ use rustc_span::Span; #[macro_use] mod plumbing; pub use plumbing::QueryCtxt; -use plumbing::QueryStruct; use rustc_query_system::query::*; mod stats; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 48eb488792d..86b12b3586a 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -219,7 +219,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for 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.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); + tcx.dep_graph.exec_cache_promotions(tcx); *self.serialized_data.write() = None; } @@ -358,23 +358,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { Ok(()) }) } - - fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId { - debug!("def_path_hash_to_def_id({:?})", hash); - - let stable_crate_id = hash.stable_crate_id(); - - // If this is a DefPathHash from the local crate, we can look up the - // DefId in the tcx's `Definitions`. - if stable_crate_id == tcx.sess.local_stable_crate_id() { - tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id() - } else { - // If this is a DefPathHash from an upstream crate, let the CrateStore map - // it to a DefId. - let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id); - tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash) - } - } } impl<'sess> OnDiskCache<'sess> { @@ -764,7 +747,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash)) + Ok(d.tcx().def_path_hash_to_def_id(def_path_hash)) } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 4d1e39db0ed..8c3fbb2071c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,7 +3,7 @@ //! manage the caches, and so forth. use crate::{on_disk_cache, queries, Queries}; -use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; @@ -53,36 +53,6 @@ impl QueryContext for QueryCtxt<'tcx> { self.queries.try_collect_active_jobs(**self) } - fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize]; - (cb.try_load_from_on_disk_cache)(*self, dep_node) - } - - fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { - debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); - - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize]; - (cb.force_from_dep_node)(*self, dep_node) - } - // Interactions with on_disk_cache fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects { self.queries @@ -193,60 +163,6 @@ impl<'tcx> QueryCtxt<'tcx> { } } -/// This struct stores metadata about each Query. -/// -/// Information is retrieved by indexing the `QUERIES` array using the integer value -/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual -/// jump table instead of large matches. -pub struct QueryStruct { - /// The red/green evaluation system will try to mark a specific DepNode in the - /// dependency graph as green by recursively trying to mark the dependencies of - /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` - /// where we don't know if it is red or green and we therefore actually have - /// to recompute its value in order to find out. Since the only piece of - /// information that we have at that point is the `DepNode` we are trying to - /// re-evaluate, we need some way to re-run a query from just that. This is what - /// `force_from_dep_node()` implements. - /// - /// In the general case, a `DepNode` consists of a `DepKind` and an opaque - /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint - /// is usually constructed by computing a stable hash of the query-key that the - /// `DepNode` corresponds to. Consequently, it is not in general possible to go - /// back from hash to query-key (since hash functions are not reversible). For - /// this reason `force_from_dep_node()` is expected to fail from time to time - /// because we just cannot find out, from the `DepNode` alone, what the - /// corresponding query-key is and therefore cannot re-run the query. - /// - /// The system deals with this case letting `try_mark_green` fail which forces - /// the root query to be re-evaluated. - /// - /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. - /// Fortunately, we can use some contextual information that will allow us to - /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we - /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a - /// valid `DefPathHash`. Since we also always build a huge table that maps every - /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have - /// everything we need to re-run the query. - /// - /// Take the `mir_promoted` query as an example. Like many other queries, it - /// just has a single parameter: the `DefId` of the item it will compute the - /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` - /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` - /// is actually a `DefPathHash`, and can therefore just look up the corresponding - /// `DefId` in `tcx.def_path_hash_to_def_id`. - /// - /// When you implement a new query, it will likely have a corresponding new - /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As - /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter, - /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just - /// add it to the "We don't have enough information to reconstruct..." group in - /// the match below. - pub(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool, - - /// Invoke a query to put the on-disk cached value in memory. - pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode), -} - macro_rules! handle_cycle_error { ([][$tcx: expr, $error:expr]) => {{ $error.emit(); @@ -291,14 +207,14 @@ macro_rules! is_eval_always { } macro_rules! hash_result { - ([][$hcx:expr, $result:expr]) => {{ - dep_graph::hash_result($hcx, &$result) + ([]) => {{ + Some(dep_graph::hash_result) }}; - ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{ + ([(no_hash) $($rest:tt)*]) => {{ None }}; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - hash_result!([$($modifiers)*][$($args)*]) + ([$other:tt $($modifiers:tt)*]) => { + hash_result!([$($modifiers)*]) }; } @@ -378,6 +294,7 @@ macro_rules! define_queries { const ANON: bool = is_anon!([$($modifiers)*]); const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]); const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name; + const HASH_RESULT: Option<fn(&mut StableHashingContext<'_>, &Self::Value) -> Fingerprint> = hash_result!([$($modifiers)*]); type Cache = query_storage::$name<$tcx>; @@ -406,13 +323,6 @@ macro_rules! define_queries { } } - fn hash_result( - _hcx: &mut StableHashingContext<'_>, - _result: &Self::Value - ) -> Option<Fingerprint> { - hash_result!([$($modifiers)*][_hcx, _result]) - } - fn handle_cycle_error( tcx: QueryCtxt<'tcx>, mut error: DiagnosticBuilder<'_>, @@ -421,7 +331,7 @@ macro_rules! define_queries { } })* - #[allow(non_upper_case_globals)] + #[allow(nonstandard_style)] pub mod query_callbacks { use super::*; use rustc_middle::dep_graph::DepNode; @@ -431,68 +341,101 @@ macro_rules! define_queries { use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. - pub const Null: QueryStruct = QueryStruct { - force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node), - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn Null() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), + try_load_from_on_disk_cache: None, + } + } - pub const TraitSelect: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn TraitSelect() -> DepKindStruct { + DepKindStruct { + is_anon: true, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - pub const CompileCodegenUnit: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn CompileCodegenUnit() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Opaque, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - pub const CompileMonoItem: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn CompileMonoItem() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Opaque, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - $(pub const $name: QueryStruct = { - const is_anon: bool = is_anon!([$($modifiers)*]); + $(pub fn $name()-> DepKindStruct { + let is_anon = is_anon!([$($modifiers)*]); + let is_eval_always = is_eval_always!([$($modifiers)*]); - #[inline(always)] - fn fingerprint_style() -> FingerprintStyle { - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>> - ::fingerprint_style() - } + let fingerprint_style = + <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style(); - fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> { - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) + if is_anon || !fingerprint_style.reconstructible() { + return DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } } - fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool { - force_query::<queries::$name<'_>, _>(tcx, dep_node) + #[inline(always)] + fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> { + <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node) } - fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) { - if is_anon { - return - } - - if !fingerprint_style().reconstructible() { - return + fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool { + if let Some(key) = recover(tcx, dep_node) { + let tcx = QueryCtxt::from_tcx(tcx); + force_query::<queries::$name<'_>, _>(tcx, key, dep_node); + true + } else { + false } + } - debug_assert!(tcx.dep_graph.is_green(dep_node)); + fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) { + debug_assert!(tcx.dep_graph.is_green(&dep_node)); - let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); + let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); + let tcx = QueryCtxt::from_tcx(tcx); if queries::$name::cache_on_disk(tcx, &key, None) { let _ = tcx.$name(key); } } - QueryStruct { - force_from_dep_node, - try_load_from_on_disk_cache, + DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: Some(force_from_dep_node), + try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), } - };)* + })* } - static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks); + pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] { + arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) + } } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 8602219a7f3..c274c2cc26c 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -60,8 +60,11 @@ impl<K: DepKind> DepNode<K> { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. - pub fn new_no_params(kind: K) -> DepNode<K> { - debug_assert!(!kind.has_params()); + pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K> + where + Ctxt: super::DepContext<DepKind = K>, + { + debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit); DepNode { kind, hash: Fingerprint::ZERO.into() } } @@ -75,7 +78,7 @@ impl<K: DepKind> DepNode<K> { #[cfg(debug_assertions)] { - if !kind.fingerprint_style().reconstructible() + if !tcx.fingerprint_style(kind).reconstructible() && (tcx.sess().opts.debugging_opts.incremental_info || tcx.sess().opts.debugging_opts.query_dep_graph) { @@ -121,11 +124,12 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T where T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug, { - #[inline] + #[inline(always)] default fn fingerprint_style() -> FingerprintStyle { FingerprintStyle::Opaque } + #[inline(always)] default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { let mut hcx = tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); @@ -135,10 +139,12 @@ where hasher.finish() } + #[inline(always)] default fn to_debug_str(&self, _: Ctxt) -> String { format!("{:?}", *self) } + #[inline(always)] default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> { None } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 114d12fb90b..a8be1ca34c0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -33,12 +33,6 @@ pub struct DepGraph<K: DepKind> { /// each task has a `DepNodeIndex` that uniquely identifies it. This unique /// ID is used for self-profiling. virtual_dep_node_index: Lrc<AtomicU32>, - - /// The cached event id for profiling node interning. This saves us - /// from having to look up the event id every time we intern a node - /// which may incur too much overhead. - /// This will be None if self-profiling is disabled. - node_intern_event_id: Option<EventId>, } rustc_index::newtype_index! { @@ -96,14 +90,13 @@ struct DepGraphData<K: DepKind> { dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>, } -pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint> +pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint where R: for<'a> HashStable<StableHashingContext<'a>>, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); - - Some(stable_hasher.finish()) + stable_hasher.finish() } impl<K: DepKind> DepGraph<K> { @@ -117,8 +110,13 @@ impl<K: DepKind> DepGraph<K> { ) -> DepGraph<K> { let prev_graph_node_count = prev_graph.node_count(); - let current = - CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats); + let current = CurrentDepGraph::new( + profiler, + prev_graph_node_count, + encoder, + record_graph, + record_stats, + ); // Instantiate a dependy-less node only once for anonymous queries. let _green_node_index = current.intern_new_node( @@ -129,10 +127,6 @@ impl<K: DepKind> DepGraph<K> { ); debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); - let node_intern_event_id = profiler - .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node") - .map(EventId::from_label); - DepGraph { data: Some(Lrc::new(DepGraphData { previous_work_products: prev_work_products, @@ -143,16 +137,11 @@ impl<K: DepKind> DepGraph<K> { colors: DepNodeColorMap::new(prev_graph_node_count), })), virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), - node_intern_event_id, } } pub fn new_disabled() -> DepGraph<K> { - DepGraph { - data: None, - virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), - node_intern_event_id: None, - } + DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. @@ -215,7 +204,7 @@ impl<K: DepKind> DepGraph<K> { cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>, + hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { if self.is_fully_enabled() { self.with_task_impl(key, cx, arg, task, hash_result) @@ -234,7 +223,7 @@ impl<K: DepKind> DepGraph<K> { cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>, + hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { // This function is only called when the graph is enabled. let data = self.data.as_ref().unwrap(); @@ -253,7 +242,7 @@ impl<K: DepKind> DepGraph<K> { key ); - let task_deps = if key.kind.is_eval_always() { + let task_deps = if cx.dep_context().is_eval_always(key.kind) { None } else { Some(Lock::new(TaskDeps { @@ -268,15 +257,14 @@ impl<K: DepKind> DepGraph<K> { let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); let dcx = cx.dep_context(); - let mut hcx = dcx.create_stable_hashing_context(); let hashing_timer = dcx.profiler().incr_result_hashing(); - let current_fingerprint = hash_result(&mut hcx, &result); + let current_fingerprint = hash_result.map(|f| { + let mut hcx = dcx.create_stable_hashing_context(); + f(&mut hcx, &result) + }); let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks; - // Get timer for profiling `DepNode` interning - let node_intern_timer = - self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid)); // Intern the new `DepNode`. let (dep_node_index, prev_and_color) = data.current.intern_node( dcx.profiler(), @@ -286,7 +274,6 @@ impl<K: DepKind> DepGraph<K> { current_fingerprint, print_status, ); - drop(node_intern_timer); hashing_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -315,7 +302,7 @@ impl<K: DepKind> DepGraph<K> { where OP: FnOnce() -> R, { - debug_assert!(!dep_kind.is_eval_always()); + debug_assert!(!cx.is_eval_always(dep_kind)); if let Some(ref data) = self.data { let task_deps = Lock::new(TaskDeps::default()); @@ -492,7 +479,7 @@ impl<K: DepKind> DepGraph<K> { tcx: Ctxt, dep_node: &DepNode<K>, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - debug_assert!(!dep_node.kind.is_eval_always()); + debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind)); // Return None if the dep graph is disabled let data = self.data.as_ref()?; @@ -552,7 +539,7 @@ impl<K: DepKind> DepGraph<K> { // We don't know the state of this dependency. If it isn't // an eval_always node, let's try to mark it green recursively. - if !dep_dep_node.kind.is_eval_always() { + if !tcx.dep_context().is_eval_always(dep_dep_node.kind) { debug!( "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \ is unknown, trying to mark it green", @@ -575,7 +562,7 @@ impl<K: DepKind> DepGraph<K> { "try_mark_previous_green({:?}) --- trying to force dependency {:?}", dep_node, dep_dep_node ); - if !tcx.try_force_from_dep_node(dep_dep_node) { + if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) { // The DepNode could not be forced. debug!( "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced", @@ -642,7 +629,7 @@ impl<K: DepKind> DepGraph<K> { } // We never try to mark eval_always nodes as green - debug_assert!(!dep_node.kind.is_eval_always()); + debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind)); debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); @@ -740,8 +727,7 @@ impl<K: DepKind> DepGraph<K> { // // This method will only load queries that will end up in the disk cache. // Other queries will not be executed. - pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt) { - let tcx = qcx.dep_context(); + pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) { let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); @@ -749,7 +735,7 @@ impl<K: DepKind> DepGraph<K> { match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { let dep_node = data.previous.index_to_node(prev_index); - qcx.try_load_from_on_disk_cache(&dep_node); + tcx.try_load_from_on_disk_cache(dep_node); } None | Some(DepNodeColor::Red) => { // We can skip red nodes because a node can only be marked @@ -876,10 +862,17 @@ pub(super) struct CurrentDepGraph<K: DepKind> { /// debugging and only active with `debug_assertions`. total_read_count: AtomicU64, total_duplicate_read_count: AtomicU64, + + /// The cached event id for profiling node interning. This saves us + /// from having to look up the event id every time we intern a node + /// which may incur too much overhead. + /// This will be None if self-profiling is disabled. + node_intern_event_id: Option<EventId>, } impl<K: DepKind> CurrentDepGraph<K> { fn new( + profiler: &SelfProfilerRef, prev_graph_node_count: usize, encoder: FileEncoder, record_graph: bool, @@ -908,6 +901,10 @@ impl<K: DepKind> CurrentDepGraph<K> { let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200; + let node_intern_event_id = profiler + .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node") + .map(EventId::from_label); + CurrentDepGraph { encoder: Steal::new(GraphEncoder::new( encoder, @@ -927,6 +924,7 @@ impl<K: DepKind> CurrentDepGraph<K> { forbidden_edge, total_read_count: AtomicU64::new(0), total_duplicate_read_count: AtomicU64::new(0), + node_intern_event_id, } } @@ -970,6 +968,10 @@ impl<K: DepKind> CurrentDepGraph<K> { ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) { let print_status = cfg!(debug_assertions) && print_status; + // Get timer for profiling `DepNode` interning + let _node_intern_timer = + self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid)); + if let Some(prev_index) = prev_graph.node_to_index_opt(&key) { // Determine the color and index of the new `DepNode`. if let Some(fingerprint) = fingerprint { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index dcda5728334..047fc9f10cc 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -32,6 +32,17 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; + + /// Return whether this kind always require evaluation. + fn is_eval_always(&self, kind: Self::DepKind) -> bool; + + fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle; + + /// Try to force a dep node to execute and see if it's green. + fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool; + + /// Load data from the on-disk cache. + fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>); } pub trait HasDepContext: Copy { @@ -51,7 +62,7 @@ impl<T: DepContext> HasDepContext for T { } /// Describes the contents of the fingerprint generated by a given query. -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum FingerprintStyle { /// The fingerprint is actually a DefPathHash. DefPathHash, @@ -75,12 +86,6 @@ impl FingerprintStyle { pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static { const NULL: Self; - /// Return whether this kind always require evaluation. - fn is_eval_always(&self) -> bool; - - /// Return whether this kind requires additional parameters to be executed. - fn has_params(&self) -> bool; - /// Implementation of `std::fmt::Debug` for `DepNode`. fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result; @@ -93,6 +98,4 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> fn read_deps<OP>(op: OP) where OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>); - - fn fingerprint_style(&self) -> FingerprintStyle; } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index f5f67fcd0a0..47197a1e492 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -222,7 +222,7 @@ impl<K: DepKind> EncoderState<K> { index } - fn finish(self) -> FileEncodeResult { + fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self; let () = result?; @@ -235,7 +235,11 @@ impl<K: DepKind> EncoderState<K> { IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?; debug!("position: {:?}", encoder.position()); // Drop the encoder so that nothing is written after the counts. - encoder.flush() + let result = encoder.flush(); + // FIXME(rylev): we hardcode the dep graph file name so we don't need a dependency on + // rustc_incremental just for that. + profiler.artifact_size("dep_graph", "dep-graph.bin", encoder.position() as u64); + result } } @@ -332,6 +336,6 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); - self.status.into_inner().finish() + self.status.into_inner().finish(profiler) } } diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index f2e935c59fc..cfef2073373 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -6,6 +6,7 @@ use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_index::vec::IndexVec; use rustc_session::cstore::CrateStore; use rustc_session::Session; use rustc_span::source_map::SourceMap; @@ -27,7 +28,6 @@ pub struct StableHashingContext<'a> { cstore: &'a dyn CrateStore, pub(super) body_resolver: BodyResolver<'a>, hash_spans: bool, - hash_bodies: bool, pub(super) node_id_hashing_mode: NodeIdHashingMode, // Very often, we are hashing something that does not need the @@ -46,24 +46,19 @@ pub enum NodeIdHashingMode { /// We could also just store a plain reference to the `hir::Crate` but we want /// to avoid that the crate is used to get untracked access to all of the HIR. #[derive(Clone, Copy)] -pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>); - -impl<'tcx> BodyResolver<'tcx> { - /// Returns a reference to the `hir::Body` with the given `BodyId`. - /// **Does not do any tracking**; use carefully. - pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> { - self.0.body(id) - } +pub(super) enum BodyResolver<'tcx> { + Forbidden, + Traverse { + hash_bodies: bool, + owner: LocalDefId, + bodies: &'tcx IndexVec<hir::ItemLocalId, Option<&'tcx hir::Body<'tcx>>>, + }, } impl<'a> StableHashingContext<'a> { - /// The `krate` here is only used for mapping `BodyId`s to `Body`s. - /// Don't use it for anything else or you'll run the risk of - /// leaking data out of the tracking system. #[inline] fn new_with_or_without_spans( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, always_ignore_spans: bool, @@ -72,13 +67,12 @@ impl<'a> StableHashingContext<'a> { !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; StableHashingContext { - body_resolver: BodyResolver(krate), + body_resolver: BodyResolver::Forbidden, definitions, cstore, caching_source_map: None, raw_source_map: sess.source_map(), hash_spans: hash_spans_initial, - hash_bodies: true, node_id_hashing_mode: NodeIdHashingMode::HashDefPath, } } @@ -86,13 +80,11 @@ impl<'a> StableHashingContext<'a> { #[inline] pub fn new( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, ) -> Self { Self::new_with_or_without_spans( sess, - krate, definitions, cstore, /*always_ignore_spans=*/ false, @@ -102,20 +94,41 @@ impl<'a> StableHashingContext<'a> { #[inline] pub fn ignore_spans( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, ) -> Self { let always_ignore_spans = true; - Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans) + Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans) } + /// Allow hashing #[inline] - pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) { - let prev_hash_bodies = self.hash_bodies; - self.hash_bodies = hash_bodies; + pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) { + let prev = match &mut self.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { ref mut hash_bodies, .. } => { + std::mem::replace(hash_bodies, hb) + } + }; f(self); - self.hash_bodies = prev_hash_bodies; + match &mut self.body_resolver { + BodyResolver::Forbidden => unreachable!(), + BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev, + } + } + + #[inline] + pub fn with_hir_bodies( + &mut self, + hash_bodies: bool, + owner: LocalDefId, + bodies: &'a IndexVec<hir::ItemLocalId, Option<&'a hir::Body<'a>>>, + f: impl FnOnce(&mut Self), + ) { + let prev = self.body_resolver; + self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies }; + f(self); + self.body_resolver = prev; } #[inline] @@ -153,11 +166,6 @@ impl<'a> StableHashingContext<'a> { } #[inline] - pub fn hash_bodies(&self) -> bool { - self.hash_bodies - } - - #[inline] pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { match self.caching_source_map { Some(ref mut sm) => sm, diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs index 04eb263a977..24f3a2e7de0 100644 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -1,12 +1,11 @@ //! This module contains `HashStable` implementations for various HIR data //! types in no particular order. +use crate::ich::hcx::BodyResolver; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_hir as hir; -use rustc_hir::definitions::DefPathHash; -use smallvec::SmallVec; use std::mem; impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { @@ -29,8 +28,13 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { #[inline] fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { let hcx = self; - if hcx.hash_bodies() { - hcx.body_resolver.body(id).hash_stable(hcx, hasher); + match hcx.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { hash_bodies: false, .. } => {} + BodyResolver::Traverse { hash_bodies: true, owner, bodies } => { + assert_eq!(id.hir_id.owner, owner); + bodies[id.hir_id.local_id].unwrap().hash_stable(hcx, hasher); + } } } @@ -115,6 +119,16 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { self.node_id_hashing_mode = prev_hash_node_ids; } + + #[inline] + fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) { + self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + let hir::TraitCandidate { def_id, import_ids } = tc; + + def_id.hash_stable(hcx, hasher); + import_ids.hash_stable(hcx, hasher); + }); + } } impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> { @@ -129,27 +143,3 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> { }); } } - -impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let hir::TraitCandidate { def_id, import_ids } = self; - - def_id.hash_stable(hcx, hasher); - import_ids.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); - - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { - let hir::TraitCandidate { def_id, import_ids } = self; - - ( - hcx.def_path_hash(*def_id), - import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), - ) - } -} diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index bc23de069b0..1b992cdb0c9 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -3,6 +3,7 @@ #![feature(core_intrinsics)] #![feature(hash_raw_entry)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(thread_local_const_init)] diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 76a165ed8e6..fc3b7980dfb 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -24,7 +24,8 @@ pub(crate) struct QueryVtable<CTX: QueryContext, K, V> { pub dep_kind: CTX::DepKind, pub eval_always: bool, - pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>, + pub compute: fn(CTX::DepContext, K) -> V, + pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>, pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool, pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>, @@ -38,12 +39,8 @@ impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> { DepNode::construct(tcx, self.dep_kind, key) } - pub(crate) fn hash_result( - &self, - hcx: &mut StableHashingContext<'_>, - value: &V, - ) -> Option<Fingerprint> { - (self.hash_result)(hcx, value) + pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V { + (self.compute)(tcx, key) } pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool { @@ -59,6 +56,9 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig { const ANON: bool; const EVAL_ALWAYS: bool; const DEP_KIND: CTX::DepKind; + const HASH_RESULT: Option< + fn(hcx: &mut StableHashingContext<'_>, result: &Self::Value) -> Fingerprint, + >; type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>; @@ -75,9 +75,6 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig { // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value; - fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value) - -> Option<Fingerprint>; - fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value; } @@ -95,7 +92,7 @@ pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> { } pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> { - const VTABLE: QueryVtable<CTX, K, V>; + fn make_vtable(tcx: CTX, key: &K) -> QueryVtable<CTX, K, V>; } impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q @@ -103,13 +100,16 @@ where CTX: QueryContext, Q: QueryDescription<CTX>, { - const VTABLE: QueryVtable<CTX, Q::Key, Q::Value> = QueryVtable { - anon: Q::ANON, - dep_kind: Q::DEP_KIND, - eval_always: Q::EVAL_ALWAYS, - hash_result: Q::hash_result, - handle_cycle_error: Q::handle_cycle_error, - cache_on_disk: Q::cache_on_disk, - try_load_from_disk: Q::try_load_from_disk, - }; + fn make_vtable(tcx: CTX, key: &Q::Key) -> QueryVtable<CTX, Q::Key, Q::Value> { + QueryVtable { + anon: Q::ANON, + dep_kind: Q::DEP_KIND, + eval_always: Q::EVAL_ALWAYS, + hash_result: Q::HASH_RESULT, + compute: Q::compute_fn(tcx, key), + handle_cycle_error: Q::handle_cycle_error, + cache_on_disk: Q::cache_on_disk, + try_load_from_disk: Q::try_load_from_disk, + } + } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 98b2a450b19..bd673030992 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -644,9 +644,7 @@ pub fn print_query_stack<CTX: QueryContext>( if Some(i) == num_frames { break; } - let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { - info - } else { + let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else { break; }; let mut diag = Diagnostic::new( diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index dffe7f3689f..e2b0a65ab77 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -14,7 +14,7 @@ pub use self::caches::{ mod config; pub use self::config::{QueryAccessors, QueryConfig, QueryDescription}; -use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; @@ -122,12 +122,6 @@ pub trait QueryContext: HasDepContext { fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>; - /// Load data from the on-disk cache. - fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>); - - /// Try to force a dep node to execute and see if it's green. - fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool; - /// Load side effects associated to the node in the previous session. fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 07d72059975..056611317dc 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,7 +2,7 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams}; +use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt}; use crate::query::job::{ @@ -382,7 +382,6 @@ fn try_execute_query<CTX, C>( lookup: QueryLookup, dep_node: Option<DepNode<CTX::DepKind>>, query: &QueryVtable<CTX, C::Key, C::Value>, - compute: fn(CTX::DepContext, C::Key) -> C::Value, ) -> (C::Stored, Option<DepNodeIndex>) where C: QueryCache, @@ -398,7 +397,7 @@ where query.dep_kind, ) { TryGetJob::NotYetStarted(job) => { - let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute); + let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id); let result = job.complete(cache, result, dep_node_index); (result, Some(dep_node_index)) } @@ -429,7 +428,6 @@ fn execute_job<CTX, K, V>( mut dep_node_opt: Option<DepNode<CTX::DepKind>>, query: &QueryVtable<CTX, K, V>, job_id: QueryJobId<CTX::DepKind>, - compute: fn(CTX::DepContext, K) -> V, ) -> (V, DepNodeIndex) where K: Clone + DepNodeParams<CTX::DepContext>, @@ -441,7 +439,7 @@ where // Fast path for when incr. comp. is off. if !dep_graph.is_fully_enabled() { let prof_timer = tcx.dep_context().profiler().query_provider(); - let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key)); + let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key)); let dep_node_index = dep_graph.next_virtual_depnode_index(); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); return (result, dep_node_index); @@ -455,7 +453,7 @@ where // The diagnostics for this query will be promoted to the current session during // `try_mark_green()`, so we can ignore them here. if let Some(ret) = tcx.start_query(job_id, None, || { - try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute) + try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query) }) { return ret; } @@ -467,14 +465,14 @@ where let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || { if query.anon { return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || { - compute(*tcx.dep_context(), key) + query.compute(*tcx.dep_context(), key) }); } // `to_dep_node` is expensive for some `DepKind`s. let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key)); - dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result) + dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result) }); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -498,7 +496,6 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>( key: &K, dep_node: &DepNode<CTX::DepKind>, query: &QueryVtable<CTX, K, V>, - compute: fn(CTX::DepContext, K) -> V, ) -> Option<(V, DepNodeIndex)> where K: Clone, @@ -520,14 +517,6 @@ where let result = query.try_load_from_disk(tcx, prev_dep_node_index); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - // We always expect to find a cached result for things that - // can be forced from `DepNode`. - debug_assert!( - !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(), - "missing on-disk cache entry for {:?}", - dep_node - ); - if let Some(result) = result { // If `-Zincremental-verify-ich` is specified, re-hash results from // the cache and make sure that they have the expected fingerprint. @@ -537,6 +526,14 @@ where return Some((result, dep_node_index)); } + + // We always expect to find a cached result for things that + // can be forced from `DepNode`. + debug_assert!( + !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), + "missing on-disk cache entry for {:?}", + dep_node + ); } // We could not load a result from the on-disk cache, so @@ -544,7 +541,7 @@ where let prof_timer = tcx.dep_context().profiler().query_provider(); // The dep-graph for this computation is already in-place. - let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone())); + let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone())); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -577,12 +574,12 @@ fn incremental_verify_ich<CTX, K, V: Debug>( ); debug!("BEGIN verify_ich({:?})", dep_node); - let mut hcx = tcx.create_stable_hashing_context(); - - let new_hash = query.hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); - debug!("END verify_ich({:?})", dep_node); - + let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| { + let mut hcx = tcx.create_stable_hashing_context(); + f(&mut hcx, result) + }); let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node); + debug!("END verify_ich({:?})", dep_node); if Some(new_hash) != old_hash { let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name { @@ -665,41 +662,6 @@ where } } -#[inline(never)] -fn force_query_impl<CTX, C>( - tcx: CTX, - state: &QueryState<CTX::DepKind, C::Key>, - cache: &QueryCacheStore<C>, - key: C::Key, - dep_node: DepNode<CTX::DepKind>, - query: &QueryVtable<CTX, C::Key, C::Value>, - compute: fn(CTX::DepContext, C::Key) -> C::Value, -) -> bool -where - C: QueryCache, - C::Key: DepNodeParams<CTX::DepContext>, - CTX: QueryContext, -{ - debug_assert!(!query.anon); - - // We may be concurrently trying both execute and force a query. - // Ensure that only one of them runs the query. - let cached = cache.cache.lookup(cache, &key, |_, index| { - if unlikely!(tcx.dep_context().profiler().enabled()) { - tcx.dep_context().profiler().query_cache_hit(index.into()); - } - }); - - let lookup = match cached { - Ok(()) => return true, - Err(lookup) => lookup, - }; - - let _ = - try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute); - true -} - pub enum QueryMode { Get, Ensure, @@ -717,9 +679,9 @@ where Q::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { - let query = &Q::VTABLE; + let query = Q::make_vtable(tcx, &key); let dep_node = if let QueryMode::Ensure = mode { - let (must_run, dep_node) = ensure_must_run(tcx, &key, query); + let (must_run, dep_node) = ensure_must_run(tcx, &key, &query); if !must_run { return None; } @@ -729,7 +691,6 @@ where }; debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span); - let compute = Q::compute_fn(tcx, &key); let (result, dep_node_index) = try_execute_query( tcx, Q::query_state(tcx), @@ -738,8 +699,7 @@ where key, lookup, dep_node, - query, - compute, + &query, ); if let Some(dep_node_index) = dep_node_index { tcx.dep_context().dep_graph().read_index(dep_node_index) @@ -747,36 +707,29 @@ where Some(result) } -pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool +pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>) where Q: QueryDescription<CTX>, Q::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { - if Q::ANON { - return false; - } + assert!(!Q::ANON); - if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() { - return false; - } + // We may be concurrently trying both execute and force a query. + // Ensure that only one of them runs the query. + let cache = Q::query_cache(tcx); + let cached = cache.cache.lookup(cache, &key, |_, index| { + if unlikely!(tcx.dep_context().profiler().enabled()) { + tcx.dep_context().profiler().query_cache_hit(index.into()); + } + }); - let key = if let Some(key) = - <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node) - { - key - } else { - return false; + let lookup = match cached { + Ok(()) => return, + Err(lookup) => lookup, }; - let compute = Q::compute_fn(tcx, &key); - force_query_impl( - tcx, - Q::query_state(tcx), - Q::query_cache(tcx), - key, - *dep_node, - &Q::VTABLE, - compute, - ) + let query = Q::make_vtable(tcx, &key); + let state = Q::query_state(tcx); + try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query); } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index f1d3315d6e6..bd27c16c732 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -23,6 +23,7 @@ rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_metadata = { path = "../rustc_metadata" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3970038a33..63000a9d13d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1327,7 +1327,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() => { // Insert a placeholder that's later replaced by `self`/`super`/etc. - path.insert(0, Segment::from_ident(Ident::invalid())); + path.insert(0, Segment::from_ident(Ident::empty())); } _ => return None, } @@ -1471,9 +1471,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { module: ModuleOrUniformRoot<'b>, ident: Ident, ) -> Option<(Option<Suggestion>, Vec<String>)> { - let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module { - module - } else { + let ModuleOrUniformRoot::Module(mut crate_module) = module else { return None; }; @@ -1837,7 +1835,7 @@ crate fn show_candidates( .skip(1) .all(|(_, descr, _)| descr == descr_first) { - format!("{}", descr_first) + descr_first.to_string() } else { "item".to_string() }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 515b2c3fd27..936ab81914a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -978,7 +978,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::invalid())); + full_path.push(Segment::from_ident(Ident::empty())); self.r.lint_if_path_starts_with_module( import.crate_lint(), &full_path, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 95633257965..0a24e00ee4b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1994,7 +1994,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if ns == ValueNS { let item_name = path.last().unwrap().ident; let traits = self.traits_in_scope(item_name, ns); - self.r.trait_map.as_mut().unwrap().insert(id, traits); + self.r.trait_map.insert(id, traits); } if PrimTy::from_name(path[0].ident.name).is_some() { @@ -2479,12 +2479,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // the field name so that we can do some nice error reporting // later on in typeck. let traits = self.traits_in_scope(ident, ValueNS); - self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); + self.r.trait_map.insert(expr.id, traits); } ExprKind::MethodCall(ref segment, ..) => { debug!("(recording candidate traits for expr) recording traits for {}", expr.id); let traits = self.traits_in_scope(segment.ident, ValueNS); - self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); + self.r.trait_map.insert(expr.id, traits); } _ => { // Nothing to do. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7b0dd82f0e6..1748a9be8e1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1552,7 +1552,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { matches!(source, PathSource::TupleStruct(..)) || source.is_call(); if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not - // suggest path with added parenthesis. + // suggest path with added parentheses. let mut suggestable_variants = variants .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index eb6f302a11d..94563400a8b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1057,9 +1057,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match param.kind { GenericParamKind::Lifetime { .. } => { let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); - let def_id = if let Region::EarlyBound(_, def_id, _) = reg { - def_id - } else { + let Region::EarlyBound(_, def_id, _) = reg else { bug!(); }; // We cannot predict what lifetimes are unused in opaque type. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9652c483686..98c1355d05b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -15,6 +15,7 @@ #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(never_type)] #![feature(nll)] #![recursion_limit = "256"] @@ -54,13 +55,14 @@ use rustc_middle::hir::exports::ExportMap; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; 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, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::source_map::{CachingSourceMapView, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -930,7 +932,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, export_map: ExportMap, - trait_map: Option<NodeMap<Vec<TraitCandidate>>>, + trait_map: NodeMap<Vec<TraitCandidate>>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1177,6 +1179,10 @@ impl ResolverAstLowering for Resolver<'_> { &mut self.definitions } + fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { + StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore()) + } + fn lint_buffer(&mut self) -> &mut LintBuffer { &mut self.lint_buffer } @@ -1185,8 +1191,8 @@ impl ResolverAstLowering for Resolver<'_> { self.next_node_id() } - fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> { - std::mem::replace(&mut self.trait_map, None).unwrap() + fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<TraitCandidate>> { + self.trait_map.remove(&node) } fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { @@ -1245,37 +1251,6 @@ impl ResolverAstLowering for Resolver<'_> { } } -struct ExpandHasher<'a, 'b> { - source_map: CachingSourceMapView<'a>, - resolver: &'a Resolver<'b>, -} - -impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> { - #[inline] - fn hash_spans(&self) -> bool { - true - } - - #[inline] - fn def_span(&self, id: LocalDefId) -> Span { - self.resolver.def_span(id) - } - - #[inline] - fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - self.resolver.def_path_hash(def_id) - } - - #[inline] - fn span_data_to_lines_and_cols( - &mut self, - span: &rustc_span::SpanData, - ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)> - { - self.source_map.span_data_to_lines_and_cols(span) - } -} - impl<'a> Resolver<'a> { pub fn new( session: &'a Session, @@ -1363,7 +1338,7 @@ impl<'a> Resolver<'a> { label_res_map: Default::default(), extern_crate_map: Default::default(), export_map: FxHashMap::default(), - trait_map: Some(NodeMap::default()), + trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, module_map, @@ -1456,13 +1431,6 @@ impl<'a> Resolver<'a> { self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) } - fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> { - ExpandHasher { - source_map: CachingSourceMapView::new(self.session.source_map()), - resolver: self, - } - } - pub fn next_node_id(&mut self) -> NodeId { let next = self .next_node_id diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 6671c7c0fa6..e32e4493726 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -500,8 +500,8 @@ impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] { d.read_seq(|d, len| { assert!(len == N); let mut v = [0u8; N]; - for x in &mut v { - *x = d.read_seq_elt(|d| Decodable::decode(d))?; + for i in 0..len { + v[i] = d.read_seq_elt(|d| Decodable::decode(d))?; } Ok(v) }) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b3d36b396c5..059b5dc5175 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1283,7 +1283,7 @@ options! { "specify the events recorded by the self profiler; for example: `-Z self-profile-events=default,query-keys` all options: none, all, default, generic-activity, query-provider, query-cache-hit - query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm"), + query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED], "make the current crate share its generic instantiations"), show_span: Option<String> = (None, parse_opt_string, [TRACKED], diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs index cea7871923b..c10968e06d7 100644 --- a/compiler/rustc_span/src/lev_distance.rs +++ b/compiler/rustc_span/src/lev_distance.rs @@ -58,34 +58,28 @@ pub fn find_best_match_for_name( let lookup = &lookup.as_str(); let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); - let (case_insensitive_match, levenshtein_match) = name_vec + // Priority of matches: + // 1. Exact case insensitive match + // 2. Levenshtein distance match + // 3. Sorted word match + if let Some(case_insensitive_match) = + name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase()) + { + return Some(*case_insensitive_match); + } + let levenshtein_match = name_vec .iter() .filter_map(|&name| { let dist = lev_distance(lookup, &name.as_str()); if dist <= max_dist { Some((name, dist)) } else { None } }) // Here we are collecting the next structure: - // (case_insensitive_match, (levenshtein_match, levenshtein_distance)) - .fold((None, None), |result, (candidate, dist)| { - ( - if candidate.as_str().to_uppercase() == lookup.to_uppercase() { - Some(candidate) - } else { - result.0 - }, - match result.1 { - None => Some((candidate, dist)), - Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }), - }, - ) + // (levenshtein_match, levenshtein_distance) + .fold(None, |result, (candidate, dist)| match result { + None => Some((candidate, dist)), + Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }), }); - // Priority of matches: - // 1. Exact case insensitive match - // 2. Levenshtein distance match - // 3. Sorted word match - if let Some(candidate) = case_insensitive_match { - Some(candidate) - } else if levenshtein_match.is_some() { + if levenshtein_match.is_some() { levenshtein_match.map(|(candidate, _)| candidate) } else { find_match_by_sorted_words(name_vec, lookup) diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs index 11822e9ef97..b32f8d32c13 100644 --- a/compiler/rustc_span/src/lev_distance/tests.rs +++ b/compiler/rustc_span/src/lev_distance/tests.rs @@ -31,17 +31,13 @@ fn test_find_best_match_for_name() { assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None); - let input = vec![Symbol::intern("aAAA")]; + let input = vec![Symbol::intern("AAAA")]; assert_eq!( - find_best_match_for_name(&input, Symbol::intern("AAAA"), None), - Some(Symbol::intern("aAAA")) + find_best_match_for_name(&input, Symbol::intern("aaaa"), None), + Some(Symbol::intern("AAAA")) ); let input = vec![Symbol::intern("AAAA")]; - // Returns None because `lev_distance > max_dist / 3` - assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None); - - let input = vec![Symbol::intern("AAAA")]; assert_eq!( find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)), Some(Symbol::intern("AAAA")) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index b79f00a8a36..74958c49849 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -653,6 +653,18 @@ impl SourceMap { }) } + /// Extends the given `Span` while the next character matches the predicate + pub fn span_extend_while( + &self, + span: Span, + f: impl Fn(char) -> bool, + ) -> Result<Span, SpanSnippetError> { + self.span_to_source(span, |s, _start, end| { + let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i); + Ok(span.with_hi(span.hi() + BytePos(n as u32))) + }) + } + /// Extends the given `Span` to just after the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { @@ -1013,6 +1025,32 @@ impl SourceMap { let source_file = &self.files()[source_file_index]; source_file.is_imported() } + + /// Gets the span of a statement. If the statement is a macro expansion, the + /// span in the context of the block span is found. The trailing semicolon is included + /// on a best-effort basis. + pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span { + if !stmt_span.from_expansion() { + return stmt_span; + } + let mac_call = original_sp(stmt_span, block_span); + self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi())) + } + + /// Tries to find the span of the semicolon of a macro call statement. + /// The input must be the *call site* span of a statement from macro expansion. + /// + /// v output + /// mac!(); + /// ^^^^^^ input + pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> { + let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?; + let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?)); + if self.span_to_snippet(span).as_deref() != Ok(";") { + return None; + } + Some(span) + } } #[derive(Clone)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fddb225345f..c25bd9bfa80 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -355,7 +355,6 @@ symbols! { await_macro, bang, begin_panic, - begin_panic_fmt, bench, bin, bind_by_move_pattern_guards, @@ -1453,7 +1452,7 @@ impl Ident { } #[inline] - pub fn invalid() -> Ident { + pub fn empty() -> Ident { Ident::with_dummy_span(kw::Empty) } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 61607159208..a57ad8f2bbd 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1117,7 +1117,7 @@ impl Niche { // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly. // If niche zero is already reserved, the selection of bounds are of little interest. let move_start = |v: WrappingRange| { - let start = v.start.wrapping_sub(1) & max_value; + let start = v.start.wrapping_sub(count) & max_value; Some((start, Scalar { value, valid_range: v.with_start(start) })) }; let move_end = |v: WrappingRange| { diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs index c55a46e69a8..414b0f7ff23 100644 --- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs +++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel}; +use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions}; pub fn opts() -> TargetOptions { let mut pre_link_args = LinkArgs::new(); @@ -13,12 +13,10 @@ pub fn opts() -> TargetOptions { disable_redzone: true, linker: Some("rust-lld".to_owned()), executables: true, - has_elf_tls: true, pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, static_position_independent_executables: true, - tls_model: TlsModel::InitialExec, ..Default::default() } } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 8fb4eb641c2..70816b5722b 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,12 +1,8 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::query::outlives_bounds::InferCtxtExt as _; use crate::traits::{self, TraitEngine, TraitEngineExt}; -use rustc_data_structures::stable_set::FxHashSet; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::ObligationCause; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse}; @@ -180,48 +176,3 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { ) } } - -pub trait OutlivesEnvironmentExt<'tcx> { - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: FxHashSet<Ty<'tcx>>, - body_id: hir::HirId, - span: Span, - ); -} - -impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: FxHashSet<Ty<'tcx>>, - body_id: hir::HirId, - span: Span, - ) { - debug!("add_implied_bounds()"); - - for ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(ty); - debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } -} diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 017a7c45bbf..1a049e6ec64 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,6 +17,7 @@ #![feature(hash_drain_filter)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c2205462680..6c5e6b1cfc3 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -4,10 +4,9 @@ use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; -use rustc_infer::infer::free_regions::FreeRegionRelations; use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{self, InferCtxt, InferOk}; +use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt}; @@ -15,19 +14,6 @@ use rustc_span::Span; use std::ops::ControlFlow; -/// Whether member constraints should be generated for all opaque types -#[derive(Debug)] -pub enum GenerateMemberConstraints { - /// The default, used by typeck - WhenRequired, - /// The borrow checker needs member constraints in any case where we don't - /// have a `'static` bound. This is because the borrow checker has more - /// flexibility in the values of regions. For example, given `f<'a, 'b>` - /// the borrow checker can have an inference variable outlive `'a` and `'b`, - /// but not be equal to `'static`. - IfNoStaticBound, -} - pub trait InferCtxtExt<'tcx> { fn instantiate_opaque_types<T: TypeFoldable<'tcx>>( &self, @@ -37,14 +23,12 @@ pub trait InferCtxtExt<'tcx> { value_span: Span, ) -> InferOk<'tcx, T>; - fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR); + fn constrain_opaque_types(&self); - fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( + fn constrain_opaque_type( &self, opaque_type_key: OpaqueTypeKey<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, - mode: GenerateMemberConstraints, - free_region_relations: &FRR, ); /*private*/ @@ -270,26 +254,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// - `opaque_types` -- the map produced by `instantiate_opaque_types` /// - `free_region_relations` -- something that can be used to relate /// the free regions (`'a`) that appear in the impl trait. - fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) { + fn constrain_opaque_types(&self) { let opaque_types = self.inner.borrow().opaque_types.clone(); for (opaque_type_key, opaque_defn) in opaque_types { - self.constrain_opaque_type( - opaque_type_key, - &opaque_defn, - GenerateMemberConstraints::WhenRequired, - free_region_relations, - ); + self.constrain_opaque_type(opaque_type_key, &opaque_defn); } } /// See `constrain_opaque_types` for documentation. - #[instrument(level = "debug", skip(self, free_region_relations))] - fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( + #[instrument(level = "debug", skip(self))] + fn constrain_opaque_type( &self, opaque_type_key: OpaqueTypeKey<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, - mode: GenerateMemberConstraints, - free_region_relations: &FRR, ) { let def_id = opaque_type_key.def_id; @@ -318,118 +295,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { hir::OpaqueTyOrigin::TyAlias => 0, }; - let span = tcx.def_span(def_id); - - // Check if the `impl Trait` bounds include region bounds. - // For example, this would be true for: - // - // fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b - // - // but false for: - // - // fn foo<'c>() -> impl Trait<'c> - // - // unless `Trait` was declared like: - // - // trait Trait<'c>: 'c - // - // in which case it would be true. - // - // This is used during regionck to decide whether we need to - // impose any additional constraints to ensure that region - // variables in `concrete_ty` wind up being constrained to - // something from `substs` (or, at minimum, things that outlive - // the fn body). (Ultimately, writeback is responsible for this - // check.) - let bounds = tcx.explicit_item_bounds(def_id); - debug!("{:#?}", bounds); - let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)); - debug!("{:#?}", bounds); - let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); - - let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds); - if !required_region_bounds.is_empty() { - 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), - }); - } - if let GenerateMemberConstraints::IfNoStaticBound = mode { - self.generate_member_constraint( - concrete_ty, - opaque_defn, - opaque_type_key, - first_own_region, - ); - } - return; - } - - // There were no `required_region_bounds`, - // so we have to search for a `least_region`. - // Go through all the regions used as arguments to the - // opaque type. These are the parameters to the opaque - // type; so in our example above, `substs` would contain - // `['a]` for the first impl trait and `'b` for the - // second. - let mut least_region = None; - - for subst_arg in &opaque_type_key.substs[first_own_region..] { - let subst_region = match subst_arg.unpack() { - GenericArgKind::Lifetime(r) => r, - GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue, - }; - - // Compute the least upper bound of it with the other regions. - debug!(?least_region); - debug!(?subst_region); - match least_region { - None => least_region = Some(subst_region), - Some(lr) => { - if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) { - // keep the current least region - } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) { - // switch to `subst_region` - least_region = Some(subst_region); - } else { - // There are two regions (`lr` and - // `subst_region`) which are not relatable. We - // can't find a best choice. Therefore, - // instead of creating a single bound like - // `'r: 'a` (which is our preferred choice), - // we will create a "in bound" like `'r in - // ['a, 'b, 'c]`, where `'a..'c` are the - // regions that appear in the impl trait. - - return self.generate_member_constraint( - concrete_ty, - opaque_defn, - opaque_type_key, - first_own_region, - ); - } - } - } - } - - let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); - debug!(?least_region); - - if let GenerateMemberConstraints::IfNoStaticBound = mode { - if least_region != tcx.lifetimes.re_static { - self.generate_member_constraint( - concrete_ty, - opaque_defn, - opaque_type_key, - first_own_region, - ); - } - } - concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - tcx, - op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), - }); + // The regions that appear in the hidden type must be equal to + // one of the regions in scope for the opaque type. + self.generate_member_constraint( + concrete_ty, + opaque_defn, + opaque_type_key, + first_own_region, + ); } /// As a fallback, we sometimes generate an "in constraint". For diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1193d10d6a7..8edb7069fc4 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -80,9 +80,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() { + walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) { Node::Leaf(leaf) => { - let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if leaf.definitely_has_param_types_or_consts(tcx) { @@ -92,7 +91,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } Node::Cast(_, _, ty) => { - let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if ty.definitely_has_param_types_or_consts(tcx) { @@ -187,8 +185,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( pub struct AbstractConst<'tcx> { // FIXME: Consider adding something like `IndexSlice` // and use this here. - pub inner: &'tcx [Node<'tcx>], - pub substs: SubstsRef<'tcx>, + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, } impl<'tcx> AbstractConst<'tcx> { @@ -218,8 +216,14 @@ impl<'tcx> AbstractConst<'tcx> { } #[inline] - pub fn root(self) -> Node<'tcx> { - self.inner.last().copied().unwrap() + pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { + let node = self.inner.last().copied().unwrap(); + match node { + Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)), + Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)), + // Don't perform substitution on the following as they can't directly contain generic params + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, + } } } @@ -542,7 +546,7 @@ where f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, ) -> ControlFlow<R> { f(ct)?; - let root = ct.root(); + let root = ct.root(tcx); match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { @@ -570,16 +574,14 @@ pub(super) fn try_unify<'tcx>( // We substitute generics repeatedly to allow AbstractConsts to unify where a // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g. // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] - while let Node::Leaf(a_ct) = a.root() { - let a_ct = a_ct.subst(tcx, a.substs); + while let Node::Leaf(a_ct) = a.root(tcx) { match AbstractConst::from_const(tcx, a_ct) { Ok(Some(a_act)) => a = a_act, Ok(None) => break, Err(_) => return true, } } - while let Node::Leaf(b_ct) = b.root() { - let b_ct = b_ct.subst(tcx, b.substs); + while let Node::Leaf(b_ct) = b.root(tcx) { match AbstractConst::from_const(tcx, b_ct) { Ok(Some(b_act)) => b = b_act, Ok(None) => break, @@ -587,10 +589,8 @@ pub(super) fn try_unify<'tcx>( } } - match (a.root(), b.root()) { + match (a.root(tcx), b.root(tcx)) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { - let a_ct = a_ct.subst(tcx, a.substs); - let b_ct = b_ct.subst(tcx, b.substs); if a_ct.ty != b_ct.ty { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1a8f863952e..970fb304879 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1038,13 +1038,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); - let (sig, body_id) = if let Some(hir::Node::Item(hir::Item { + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node - { - (sig, body_id) - } else { + else { return false; }; let body = hir.body(*body_id); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0bb00dfeb43..afc546540d2 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -647,9 +647,7 @@ fn receiver_is_dispatchable<'tcx>( debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); - let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { - (u, cu) - } else { + let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else { debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); return false; }; @@ -839,14 +837,13 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // constants which are not considered const evaluatable. use rustc_middle::thir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { - Node::Leaf(leaf) => { - let leaf = leaf.subst(self.tcx, ct.substs); - self.visit_const(leaf) - } - Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { + match node.root(self.tcx) { + Node::Leaf(leaf) => self.visit_const(leaf), + Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } } }) } else { diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 209fd83b3ab..85ca4db7d74 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -164,9 +164,7 @@ impl<'tcx> OnUnimplementedDirective { ) -> Result<Option<Self>, ErrorReported> { let attrs = tcx.get_attrs(impl_def_id); - let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) { - item - } else { + let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else { return Ok(None); }; diff --git a/compiler/rustc_trait_selection/src/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs index f6f42814d3f..ef349367813 100644 --- a/compiler/rustc_trait_selection/src/traits/query/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs @@ -9,7 +9,6 @@ pub mod dropck_outlives; pub mod evaluate_obligation; pub mod method_autoderef; pub mod normalize; -pub mod outlives_bounds; pub mod type_op; pub use rustc_middle::traits::query::*; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 03087e3353a..04c382d439d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::Fallible; +use rustc_infer::traits::query::OutlivesBound; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 856ea43b1ff..74e132097cc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -716,9 +716,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), ); - let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() { - data - } else { + let ty::Dynamic(data, ..) = normalized_ty.kind() else { return None; }; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 1d10d068490..37e00733737 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -4,14 +4,14 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::TraitEngineExt as _; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; use rustc_trait_selection::traits::wf; use rustc_trait_selection::traits::FulfillmentContext; @@ -118,7 +118,7 @@ fn compute_implied_outlives_bounds<'tcx>( ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { let ty_a = infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; - tcx.push_outlives_components(ty_a, &mut components); + push_outlives_components(tcx, ty_a, &mut components); implied_bounds_from_components(r_b, components) } }, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 3d3b2743700..bc77c94809e 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{ self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, @@ -478,11 +477,11 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { let node = tcx.hir().get(hir_id); - let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| { + let fn_kind = node.fn_kind().unwrap_or_else(|| { bug!("asyncness: expected fn-like node but got `{:?}`", def_id); }); - fn_like.asyncness() + fn_kind.asyncness() } /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 889b68773c2..da751f20753 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1916,9 +1916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); - let self_ty = if let Some(ty) = opt_self_ty { - ty - } else { + let Some(self_ty) = opt_self_ty else { let path_str = tcx.def_path_str(trait_def_id); let def_id = self.item_def_id(); diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index ff04e07acc4..24474e163b9 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -64,16 +64,16 @@ impl<'tcx> Bounds<'tcx> { }) }); - self.region_bounds - .iter() - .map(|&(region_bound, span)| { + sized_predicate + .into_iter() + .chain(self.region_bounds.iter().map(|&(region_bound, span)| { ( region_bound .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) .to_predicate(tcx), span, ) - }) + })) .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); (predicate, span) @@ -83,7 +83,6 @@ impl<'tcx> Bounds<'tcx> { .iter() .map(|&(projection, span)| (projection.to_predicate(tcx), span)), ) - .chain(sized_predicate.into_iter()) .collect() } } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 06c42098791..5d22e300774 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let end = callee_span.shrink_to_hi(); err.multipart_suggestion( "if you meant to create this closure and immediately call it, surround the \ - closure with parenthesis", + closure with parentheses", vec![(start, "(".to_string()), (end, ")".to_string())], Applicability::MaybeIncorrect, ); @@ -383,7 +383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, &format!( "`{}` is a unit variant, you need to write it \ - without the parenthesis", + without the parentheses", path ), path.to_string(), diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index a87318ff34e..40f456de183 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -521,9 +521,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); - let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { - (u, cu) - } else { + let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { debug!("missing Unsize or CoerceUnsized traits"); return Err(TypeError::Mismatch); }; diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 540365956a8..2b3672211e4 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -743,9 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - src - } else { + let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else { return false; }; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7b9629e534b..ac4bb652244 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1171,8 +1171,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { return None; } - let original_span = original_sp(last_stmt.span, blk.span); - Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box)) + let span = if last_stmt.span.from_expansion() { + let mac_call = original_sp(last_stmt.span, blk.span); + self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? + } else { + last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + }; + Some((span, needs_box)) } // Instantiates the given path, which must refer to an item with the given diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 79e004a47db..aea1bcd95df 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { other_ty: Ty<'tcx>, op: hir::BinOp, is_assign: IsAssign, - ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { + ) -> bool /* did we suggest to call a function because of missing parentheses? */ { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = *ty.kind() { let source_map = self.tcx.sess.source_map(); @@ -502,9 +502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: Instead of exiting early when encountering bound vars in // the function signature, consider keeping the binder here and // propagating it downwards. - let fn_sig = if let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() { - fn_sig - } else { + let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else { return false; }; diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 635219146d0..5aa11cce25f 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -718,10 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. - let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) - { - variant_ty - } else { + let Some((variant, pat_ty)) = self.check_struct_path(qpath, pat.hir_id) else { let err = self.tcx.ty_error(); for field in fields { let ti = TopInfo { parent_pat: Some(pat), ..ti }; diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index 849bf1e455c..5d9e6ebd50c 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -411,9 +411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_op_to_mutable: method={:?}", method); self.write_method_call(expr.hir_id, method); - let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() { - r - } else { + let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else { span_bug!(expr.span, "input to mutable place op is not a mut ref?"); }; diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 79443010fbb..f945a2e5063 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -76,19 +76,19 @@ use crate::check::dropck; use crate::check::FnCtxt; use crate::mem_categorization as mc; use crate::middle::region; +use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::PatKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{self, RegionObligation, RegionckMode}; +use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode}; use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::infer::OutlivesEnvironmentExt; -use rustc_trait_selection::opaque_types::InferCtxtExt; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; use std::ops::Deref; // a variation on try that just returns unit @@ -104,6 +104,51 @@ macro_rules! ignore_err { }; } +trait OutlivesEnvironmentExt<'tcx> { + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: FxHashSet<Ty<'tcx>>, + body_id: hir::HirId, + span: Span, + ); +} + +impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { + /// This method adds "implied bounds" into the outlives environment. + /// Implied bounds are outlives relationships that we can deduce + /// on the basis that certain types must be well-formed -- these are + /// either the types that appear in the function signature or else + /// the input types to an impl. For example, if you have a function + /// like + /// + /// ``` + /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } + /// ``` + /// + /// we can assume in the caller's body that `'b: 'a` and that `T: + /// 'b` (and hence, transitively, that `T: 'a`). This method would + /// add those assumptions into the outlives-environment. + /// + /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: FxHashSet<Ty<'tcx>>, + body_id: hir::HirId, + span: Span, + ) { + debug!("add_implied_bounds()"); + + for ty in fn_sig_tys { + let ty = infcx.resolve_vars_if_possible(ty); + debug!("add_implied_bounds: ty = {}", ty); + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + self.add_outlives_bounds(Some(infcx), implied_bounds) + } + } +} + /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS @@ -296,7 +341,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_body(body); self.visit_region_obligations(body_id.hir_id); - self.constrain_opaque_types(self.outlives_environment.free_region_map()); + self.constrain_opaque_types(); } fn visit_region_obligations(&mut self, hir_id: hir::HirId) { diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 3a10988bba0..9c7b0b2cacb 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -883,8 +883,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.get_diagnostic_item(sym::unwind_safe_trait), self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), ]; - let auto_traits = - vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; + const AUTO_TRAITS: [&str; 6] = + ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; @@ -957,7 +957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // by the root variable but not by the capture for (idx, _) in obligations_should_hold.iter().enumerate() { if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] { - capture_problems.insert(auto_traits[idx]); + capture_problems.insert(AUTO_TRAITS[idx]); } } @@ -1000,11 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let root_var_min_capture_list = if let Some(root_var_min_capture_list) = - min_captures.and_then(|m| m.get(&var_hir_id)) - { - root_var_min_capture_list - } else { + let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else { // The upvar is mentioned within the closure but no path starting from it is // used. @@ -1077,10 +1073,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, ) -> (Vec<MigrationDiagnosticInfo>, String) { - let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - upvars - } else { - return (Vec::new(), format!("")); + let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else { + return (Vec::new(), String::new()); }; let mut need_migrations = Vec::new(); @@ -1684,9 +1678,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { diag_expr_id: hir::HirId, ) { let tcx = self.fcx.tcx; - let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { - upvar_id - } else { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return; }; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 20cf9a75e12..30aab38b1eb 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -142,23 +142,23 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } hir::ItemKind::Fn(ref sig, ..) => { - check_item_fn(tcx, item.hir_id(), item.ident, item.span, sig.decl); + check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl); } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, item.hir_id(), ty.span, false); + check_item_type(tcx, item.def_id, ty.span, false); } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, item.hir_id(), ty.span, false); + check_item_type(tcx, item.def_id, ty.span, false); } hir::ItemKind::ForeignMod { items, .. } => { for it in items.iter() { let it = tcx.hir().foreign_item(it.id); match it.kind { hir::ForeignItemKind::Fn(decl, ..) => { - check_item_fn(tcx, it.hir_id(), it.ident, it.span, decl) + check_item_fn(tcx, it.def_id, it.ident, it.span, decl) } hir::ForeignItemKind::Static(ty, ..) => { - check_item_type(tcx, it.hir_id(), ty.span, true) + check_item_type(tcx, it.def_id, ty.span, true) } hir::ForeignItemKind::Type => (), } @@ -199,7 +199,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { _ => (None, trait_item.span), }; check_object_unsafe_self_trait_by_name(tcx, trait_item); - check_associated_item(tcx, trait_item.hir_id(), span, method_sig); + check_associated_item(tcx, trait_item.def_id, span, method_sig); let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id); let encl_trait = tcx.hir().expect_item(encl_trait_hir_id); @@ -327,7 +327,7 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.hir_id(), span, method_sig); + check_associated_item(tcx, impl_item.def_id, span, method_sig); } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { @@ -437,13 +437,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, + item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))); + let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(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)); + let item = fcx.tcx.associated_item(item_id); let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param), @@ -455,11 +455,7 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -481,11 +477,8 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = + fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -496,14 +489,13 @@ fn check_associated_item( } fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { - for_id(tcx, item.hir_id(), item.span) + for_id(tcx, item.def_id, item.span) } -fn for_id(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'_> { - let def_id = tcx.hir().local_def_id(id); +fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { CheckWfFcxBuilder { inherited: Inherited::build(tcx, def_id), - id, + id: hir::HirId::make_owner(def_id), span, param_env: tcx.param_env(def_id), } @@ -665,13 +657,12 @@ fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span fn check_item_fn( tcx: TyCtxt<'_>, - item_id: hir::HirId, + def_id: LocalDefId, ident: Ident, span: Span, decl: &hir::FnDecl<'_>, ) { - for_id(tcx, item_id, span).with_fcx(|fcx| { - let def_id = tcx.hir().local_def_id(item_id); + for_id(tcx, def_id, span).with_fcx(|fcx| { let sig = tcx.fn_sig(def_id); let mut implied_bounds = FxHashSet::default(); check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds); @@ -679,16 +670,12 @@ fn check_item_fn( }) } -fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_foreign_ty: bool) { +fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { debug!("check_item_type: {:?}", item_id); for_id(tcx, item_id, ty_span).with_fcx(|fcx| { - let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in_wf( - ty_span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = tcx.type_of(item_id); + let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, WellFormedLoc::Ty(item_id)); let mut forbid_unsized = true; if allow_foreign_ty { @@ -701,7 +688,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo fcx.register_wf_obligation( item_ty.into(), ty_span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))), ); if forbid_unsized { fcx.register_bound( diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 971776c882a..017e7ad8ca7 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -63,6 +63,7 @@ This API is completely unstable and subject to change. #![feature(in_band_lifetimes)] #![feature(is_sorted)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(nll)] #![feature(try_blocks)] diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 957ff252519..eb3853b6b3d 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -9,6 +9,7 @@ use rustc_span::Span; mod explicit; mod implicit_infer; +crate mod outlives_bounds; /// Code to write unit test for outlives. pub mod test; mod utils; diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs index f5fa52c915d..4ab5fe26abe 100644 --- a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs +++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs @@ -1,11 +1,11 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine}; use rustc_hir as hir; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; +use rustc_trait_selection::infer::canonical::OriginalQueryValues; +use rustc_trait_selection::infer::InferCtxt; +use rustc_trait_selection::traits::query::NoSolution; +use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine}; pub use rustc_middle::traits::query::OutlivesBound; diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs index 8b069678796..76ae2ee4356 100644 --- a/compiler/rustc_typeck/src/outlives/utils.rs +++ b/compiler/rustc_typeck/src/outlives/utils.rs @@ -1,4 +1,4 @@ -use rustc_middle::ty::outlives::Component; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt}; use rustc_span::Span; @@ -35,7 +35,7 @@ pub fn insert_outlives_predicate<'tcx>( // Or if within `struct Foo<U>` you had `T = Vec<U>`, then // we would want to add `U: 'outlived_region` let mut components = smallvec![]; - tcx.push_outlives_components(ty, &mut components); + push_outlives_components(tcx, ty, &mut components); for component in components { match component { Component::Region(r) => { |
