diff options
Diffstat (limited to 'compiler/rustc_passes/src')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 283 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_const.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/dead.rs | 86 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/entry.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/hir_id_validator.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/hir_stats.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/intrinsicck.rs | 36 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/lang_items.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/layout_test.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/lib.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/lib_features.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/liveness.rs | 74 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/loops.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/naked_functions.rs | 130 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/reachable.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/region.rs | 55 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/stability.rs | 57 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/upvars.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/weak_lang_items.rs | 22 | 
19 files changed, 523 insertions, 433 deletions
| diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 596d13d2d9a..c3d5bae32e6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,25 +4,25 @@ //! conflicts between multiple such attributes attached to the same //! item. -use rustc_middle::hir::map::Map; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; - use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability}; -use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID}; use rustc_hir::{MethodKind, Target}; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; +use std::collections::hash_map::Entry; pub(crate) fn target_from_impl_item<'tcx>( tcx: TyCtxt<'tcx>, @@ -57,7 +57,7 @@ struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, } -impl CheckAttrVisitor<'tcx> { +impl CheckAttrVisitor<'_> { /// Checks any attribute. fn check_attributes( &self, @@ -69,7 +69,7 @@ impl CheckAttrVisitor<'tcx> { let mut doc_aliases = FxHashMap::default(); let mut is_valid = true; let mut specified_inline = None; - let mut seen = FxHashSet::default(); + let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { let attr_is_valid = match attr.name_or_empty() { @@ -112,6 +112,8 @@ impl CheckAttrVisitor<'tcx> { self.check_default_method_body_is_const(attr, span, target) } sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), + sym::must_use => self.check_must_use(hir_id, &attr, span, target), + sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -124,6 +126,7 @@ impl CheckAttrVisitor<'tcx> { // lint-only checks match attr.name_or_empty() { sym::cold => self.check_cold(hir_id, attr, span, target), + sym::link => self.check_link(hir_id, attr, span, target), sym::link_name => self.check_link_name(hir_id, attr, span, target), sym::link_section => self.check_link_section(hir_id, attr, span, target), sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target), @@ -132,7 +135,6 @@ impl CheckAttrVisitor<'tcx> { } sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target), sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]), - sym::cfg_attr => self.check_cfg_attr(hir_id, attr), sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target), sym::ignore | sym::should_panic | sym::proc_macro_derive => { @@ -147,8 +149,10 @@ impl CheckAttrVisitor<'tcx> { _ => {} } + let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + if hir_id != CRATE_HIR_ID { - if let Some((_, AttributeType::CrateLevel, ..)) = + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { @@ -164,21 +168,37 @@ impl CheckAttrVisitor<'tcx> { } } - // Duplicate attributes - match attr.name_or_empty() { - name @ sym::macro_use => { - let args = attr.meta_item_list().unwrap_or_else(Vec::new); - let args: Vec<_> = args.iter().map(|arg| arg.name_or_empty()).collect(); - if !seen.insert((name, args)) { - self.tcx.struct_span_lint_hir( - UNUSED_ATTRIBUTES, - hir_id, + if let Some(BuiltinAttribute { duplicates, .. }) = builtin { + check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen); + } + + // Warn on useless empty attributes. + if matches!( + attr.name_or_empty(), + sym::macro_use + | sym::allow + | sym::warn + | sym::deny + | sym::forbid + | sym::feature + | sym::repr + | sym::target_feature + ) && attr.meta_item_list().map_or(false, |list| list.is_empty()) + { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("unused attribute") + .span_suggestion( attr.span, - |lint| lint.build("unused attribute").emit(), - ); - } - } - _ => {} + "remove this attribute", + String::new(), + Applicability::MachineApplicable, + ) + .note(&format!( + "attribute `{}` with an empty list has no effect", + attr.name_or_empty() + )) + .emit(); + }); } } @@ -362,7 +382,7 @@ impl CheckAttrVisitor<'tcx> { &self, hir_id: HirId, attr_span: &Span, - attrs: &'hir [Attribute], + attrs: &[Attribute], span: &Span, target: Target, ) -> bool { @@ -587,7 +607,7 @@ impl CheckAttrVisitor<'tcx> { return err_fn(meta.span(), &format!("isn't allowed on {}", err)); } let item_name = self.tcx.hir().name(hir_id); - if &*item_name.as_str() == doc_alias { + if item_name.as_str() == doc_alias { return err_fn(meta.span(), "is the same as the item's name"); } let span = meta.span(); @@ -616,7 +636,7 @@ impl CheckAttrVisitor<'tcx> { LitKind::Str(s, _) => { if !self.check_doc_alias_value( v, - &s.as_str(), + s.as_str(), hir_id, target, true, @@ -812,7 +832,7 @@ impl CheckAttrVisitor<'tcx> { let mut err = lint.build( "this attribute can only be applied at the crate level", ); - if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_HIR_ID { + if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID { if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { @@ -962,7 +982,7 @@ impl CheckAttrVisitor<'tcx> { } sym::primitive => { - if !self.tcx.features().doc_primitive { + if !self.tcx.features().rustdoc_internals { self.tcx.struct_span_lint_hir( INVALID_DOC_ATTRIBUTES, hir_id, @@ -1046,6 +1066,55 @@ impl CheckAttrVisitor<'tcx> { is_valid } + /// Warns against some misuses of `#[pass_by_value]` + fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Struct | Target::Enum | Target::TyAlias => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "`pass_by_value` attribute should be applied to a struct, enum or type alias.", + ) + .span_label(*span, "is not a struct, enum or type alias") + .emit(); + false + } + } + } + + /// Warns against some misuses of `#[must_use]` + fn check_must_use( + &self, + hir_id: HirId, + attr: &Attribute, + span: &Span, + _target: Target, + ) -> bool { + let node = self.tcx.hir().get(hir_id); + if let Some(fn_node) = node.fn_kind() { + if let rustc_hir::IsAsync::Async = fn_node.asyncness() { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build( + "`must_use` attribute on `async` functions \ + applies to the anonymous `Future` returned by the \ + function, not the value within", + ) + .span_label( + *span, + "this attribute does nothing, the `Future`s \ + returned by async functions are already `must_use`", + ) + .emit(); + }); + } + } + + // For now, its always valid + true + } + /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid. fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool { match target { @@ -1089,6 +1158,26 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if `#[link]` is applied to an item other than a foreign module. + fn check_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::ForeignMod => {} + _ => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = lint.build("attribute should be applied to an `extern` block"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + + diag.span_label(*span, "not an `extern` block"); + diag.emit(); + }); + } + } + } + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { @@ -1430,7 +1519,7 @@ impl CheckAttrVisitor<'tcx> { /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, - attrs: &'hir [Attribute], + attrs: &[Attribute], span: &Span, target: Target, item: Option<ItemLike<'_>>, @@ -1612,7 +1701,7 @@ impl CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attrs: &'hir [Attribute], target: Target) { + fn check_used(&self, attrs: &[Attribute], target: Target) { for attr in attrs { if attr.has_name(sym::used) && target != Target::Static { self.tcx @@ -1772,16 +1861,6 @@ impl CheckAttrVisitor<'tcx> { } } - fn check_cfg_attr(&self, hir_id: HirId, attr: &Attribute) { - if let Some((_, attrs)) = rustc_parse::parse_cfg_attr(&attr, &self.tcx.sess.parse_sess) { - if attrs.is_empty() { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[cfg_attr]` does not expand to any attributes").emit(); - }); - } - } - } - fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::Fn { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { @@ -1791,11 +1870,11 @@ impl CheckAttrVisitor<'tcx> { } } -impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { - type Map = Map<'tcx>; +impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_item(&mut self, item: &'tcx Item<'tcx>) { @@ -1902,7 +1981,12 @@ fn is_c_like_enum(item: &Item<'_>) -> bool { } } +// FIXME: Fix "Cannot determine resolution" error and remove built-in macros +// from this check. fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { + // Check for builtin attributes at the crate level + // which were unsuccessfully resolved due to cannot determine + // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ sym::macro_export, sym::repr, @@ -1910,20 +1994,39 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { sym::automatically_derived, sym::start, sym::rustc_main, + sym::derive, + sym::test, + sym::test_case, + sym::global_allocator, + sym::bench, ]; for attr in attrs { - for attr_to_check in ATTRS_TO_CHECK { - if attr.has_name(*attr_to_check) { - tcx.sess - .struct_span_err( + // This function should only be called with crate attributes + // which are inner attributes always but lets check to make sure + if attr.style == AttrStyle::Inner { + for attr_to_check in ATTRS_TO_CHECK { + if attr.has_name(*attr_to_check) { + let mut err = tcx.sess.struct_span_err( attr.span, &format!( "`{}` attribute cannot be used at crate level", attr_to_check.to_ident_string() ), - ) - .emit(); + ); + // Only emit an error with a suggestion if we can create a + // string out of the attribute span + if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) { + let replacement = src.replace("#!", "#"); + err.span_suggestion_verbose( + attr.span, + "perhaps you meant to use an outer attribute", + replacement, + rustc_errors::Applicability::MachineApplicable, + ); + } + err.emit() + } } } } @@ -1958,3 +2061,77 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_attrs, ..*providers }; } + +fn check_duplicates( + tcx: TyCtxt<'_>, + attr: &Attribute, + hir_id: HirId, + duplicates: AttributeDuplicates, + seen: &mut FxHashMap<Symbol, Span>, +) { + use AttributeDuplicates::*; + if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() { + return; + } + match duplicates { + DuplicatesOk => {} + WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => { + match seen.entry(attr.name_or_empty()) { + Entry::Occupied(mut entry) => { + let (this, other) = if matches!(duplicates, FutureWarnPreceding) { + let to_remove = entry.insert(attr.span); + (to_remove, attr.span) + } else { + (attr.span, *entry.get()) + }; + tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| { + let mut db = lint.build("unused attribute"); + db.span_note(other, "attribute also specified here").span_suggestion( + this, + "remove this attribute", + String::new(), + Applicability::MachineApplicable, + ); + if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) { + db.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + } + db.emit(); + }); + } + Entry::Vacant(entry) => { + entry.insert(attr.span); + } + } + } + ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) { + Entry::Occupied(mut entry) => { + let (this, other) = if matches!(duplicates, ErrorPreceding) { + let to_remove = entry.insert(attr.span); + (to_remove, attr.span) + } else { + (attr.span, *entry.get()) + }; + tcx.sess + .struct_span_err( + this, + &format!("multiple `{}` attributes", attr.name_or_empty()), + ) + .span_note(other, "attribute also specified here") + .span_suggestion( + this, + "remove this attribute", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + Entry::Vacant(entry) => { + entry.insert(attr.span); + } + }, + } +} diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index a0ceb567f25..2b11f6b0c1d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -11,8 +11,8 @@ use rustc_attr as attr; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_middle::hir::map::Map; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -78,7 +78,7 @@ impl<'tcx> CheckConstTraitVisitor<'tcx> { impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> { /// check for const trait impls, and errors if the impl uses provided/default functions /// of the trait being implemented; as those provided functions can be non-const. - fn visit_item(&mut self, item: &'hir hir::Item<'hir>) { + fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) { let _: Option<_> = try { if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::Constness::Const = imp.constness { @@ -93,26 +93,29 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() { if let ty::AssocItem { - kind: ty::AssocKind::Fn, ident, defaultness, .. - } = trait_item + kind: ty::AssocKind::Fn, + defaultness, + def_id: trait_item_id, + .. + } = *trait_item { // we can ignore functions that do not have default bodies: // if those are unimplemented it will be catched by typeck. if !defaultness.has_value() || self .tcx - .has_attr(trait_item.def_id, sym::default_method_body_is_const) + .has_attr(trait_item_id, sym::default_method_body_is_const) { continue; } let is_implemented = ancestors - .leaf_def(self.tcx, trait_item.ident, trait_item.kind) + .leaf_def(self.tcx, trait_item_id) .map(|node_item| !node_item.defining_node.is_from_trait()) .unwrap_or(false); if !is_implemented { - to_implement.push(ident.to_string()); + to_implement.push(self.tcx.item_name(trait_item_id).to_string()); } } } @@ -134,11 +137,11 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< }; } - fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {} + fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {} - fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {} + fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {} - fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {} + fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {} } #[derive(Copy, Clone)] @@ -173,6 +176,12 @@ impl<'tcx> CheckConstVisitor<'tcx> { None => return true, }; + // If the function belongs to a trait, then it must enable the const_trait_impl + // feature to use that trait function (with a const default body). + if tcx.trait_of_item(def_id).is_some() { + return true; + } + // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { @@ -210,10 +219,10 @@ impl<'tcx> CheckConstVisitor<'tcx> { required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { - &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(), + [] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(), - &[missing_primary, ref missing_secondary @ ..] => { - let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg); + [missing_primary, ref missing_secondary @ ..] => { + let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg); // If multiple feature gates would be required to enable this expression, include // them as help messages. Don't emit a separate error for each missing feature gate. @@ -253,10 +262,10 @@ impl<'tcx> CheckConstVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { - type Map = Map<'tcx>; + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 77279132401..7f15aacc532 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -3,18 +3,20 @@ // from live codes are live, and everything else is dead. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; -use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; use std::mem; // Any local node that may call something in its body block should be @@ -23,7 +25,7 @@ use std::mem; // may need to be marked as live. fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!( - tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)), + tcx.hir().find_by_def_id(def_id), Some( Node::Item(..) | Node::ImplItem(..) @@ -47,6 +49,10 @@ struct MarkSymbolVisitor<'tcx> { ignore_variant_stack: Vec<DefId>, // maps from tuple struct constructors to tuple struct items struct_constructors: FxHashMap<LocalDefId, LocalDefId>, + // maps from ADTs to ignored derived traits (e.g. Debug and Clone) + // and the span of their respective impl (i.e., part of the derive + // macro) + ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>, } impl<'tcx> MarkSymbolVisitor<'tcx> { @@ -150,7 +156,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands. fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) { - fn check_for_self_assign_helper( + fn check_for_self_assign_helper<'tcx>( tcx: TyCtxt<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, lhs: &'tcx hir::Expr<'tcx>, @@ -232,7 +238,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { // tuple struct constructor function let id = self.struct_constructors.get(&id).copied().unwrap_or(id); - if let Some(node) = self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(id)) { + if let Some(node) = self.tcx.hir().find_by_def_id(id) { self.live_symbols.insert(id); self.visit_node(node); } @@ -242,7 +248,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// Automatically generated items marked with `rustc_trivial_field_reads` /// will be ignored for the purposes of dead code analysis (see PR #85200 /// for discussion). - fn should_ignore_item(&self, def_id: DefId) -> bool { + fn should_ignore_item(&mut self, def_id: DefId) -> bool { if let Some(impl_of) = self.tcx.impl_of_method(def_id) { if !self.tcx.has_attr(impl_of, sym::automatically_derived) { return false; @@ -250,6 +256,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) { if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { + let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap(); + if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { + let impl_span = self.tcx.def_span(impl_of); + if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) { + v.push((impl_span, trait_of)); + } else { + self.ignored_derived_traits + .insert(adt_def.did, vec![(impl_span, trait_of)]); + } + } return true; } } @@ -323,12 +339,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_nested_body(&mut self, body: hir::BodyId) { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); @@ -577,7 +587,7 @@ fn create_and_seed_worklist<'tcx>( fn find_live<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, -) -> FxHashSet<LocalDefId> { +) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) { let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels); let mut symbol_visitor = MarkSymbolVisitor { worklist, @@ -590,17 +600,19 @@ fn find_live<'tcx>( pub_visibility: false, ignore_variant_stack: vec![], struct_constructors, + ignored_derived_traits: FxHashMap::default(), }; symbol_visitor.mark_live_symbols(); - symbol_visitor.live_symbols + (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits) } struct DeadVisitor<'tcx> { tcx: TyCtxt<'tcx>, live_symbols: FxHashSet<LocalDefId>, + ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>, } -impl DeadVisitor<'tcx> { +impl<'tcx> DeadVisitor<'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool { let should_warn = matches!( item.kind, @@ -666,21 +678,51 @@ impl DeadVisitor<'tcx> { self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| { let def_id = self.tcx.hir().local_def_id(id); let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); - lint.build(&format!("{} is never {}: `{}`", descr, participle, name)).emit() + let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name)); + let hir = self.tcx.hir(); + if let Some(encl_scope) = hir.get_enclosing_scope(id) { + if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) { + if let Some(ign_traits) = + self.ignored_derived_traits.get(&encl_def_id.to_def_id()) + { + let traits_str = ign_traits + .iter() + .map(|(_, t)| format!("`{}`", self.tcx.item_name(*t))) + .collect::<Vec<_>>() + .join(" and "); + let plural_s = pluralize!(ign_traits.len()); + let article = if ign_traits.len() > 1 { "" } else { "a " }; + let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" }; + let msg = format!( + "`{}` has {}derived impl{} for the trait{} {}, but {} \ + intentionally ignored during dead code analysis", + self.tcx.item_name(encl_def_id.to_def_id()), + article, + plural_s, + plural_s, + traits_str, + is_are + ); + let multispan = ign_traits.iter().map(|(s, _)| *s).collect::<Vec<_>>(); + err.span_note(multispan, &msg); + } + } + } + err.emit(); }); } } } -impl Visitor<'tcx> for DeadVisitor<'tcx> { - type Map = Map<'tcx>; +impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> { + type NestedFilter = nested_filter::All; /// Walk nested items in place so that we don't report dead-code /// on inner functions when the outer function is already getting /// an error. We could do this also by checking the parents, but /// this is how the code is setup and it seems harmless enough. - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::All(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { @@ -796,7 +838,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { pub fn check_crate(tcx: TyCtxt<'_>) { let access_levels = &tcx.privacy_access_levels(()); - let live_symbols = find_live(tcx, access_levels); - let mut visitor = DeadVisitor { tcx, live_symbols }; + let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels); + let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; tcx.hir().walk_toplevel_module(&mut visitor); } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 63f9b3ed6b1..fdabe41dafa 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,8 +1,8 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID}; +use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -18,14 +18,14 @@ struct EntryContext<'a, 'tcx> { map: Map<'tcx>, /// The function that has attribute named `main`. - attr_main_fn: Option<(HirId, Span)>, + attr_main_fn: Option<(LocalDefId, Span)>, /// The function that has the attribute 'start' on it. - start_fn: Option<(HirId, Span)>, + start_fn: Option<(LocalDefId, Span)>, /// The functions that one might think are `main` but aren't, e.g. /// main functions not defined at the top level. For diagnostics. - non_main_fns: Vec<(HirId, Span)>, + non_main_fns: Vec<Span>, } impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { @@ -112,11 +112,11 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { } EntryPointType::MainNamed => (), EntryPointType::OtherMain => { - ctxt.non_main_fns.push((item.hir_id(), item.span)); + ctxt.non_main_fns.push(item.span); } EntryPointType::MainAttr => { if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((item.hir_id(), item.span)); + ctxt.attr_main_fn = Some((item.def_id, item.span)); } else { struct_span_err!( ctxt.session, @@ -131,7 +131,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { } EntryPointType::Start => { if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((item.hir_id(), item.span)); + ctxt.start_fn = Some((item.def_id, item.span)); } else { struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions") .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here") @@ -143,20 +143,19 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { } fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> { - if let Some((hir_id, _)) = visitor.start_fn { - Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start)) - } else if let Some((hir_id, _)) = visitor.attr_main_fn { - Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main)) + if let Some((def_id, _)) = visitor.start_fn { + Some((def_id.to_def_id(), EntryFnType::Start)) + } else if let Some((def_id, _)) = visitor.attr_main_fn { + Some((def_id.to_def_id(), EntryFnType::Main)) } else { if let Some(main_def) = tcx.resolutions(()).main_def { if let Some(def_id) = main_def.opt_fn_def_id() { // non-local main imports are handled below - if def_id.is_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if matches!(tcx.hir().find(hir_id), Some(Node::ForeignItem(_))) { + if let Some(def_id) = def_id.as_local() { + if matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) { tcx.sess .struct_span_err( - tcx.hir().span(hir_id), + tcx.def_span(def_id), "the `main` function cannot be declared in an `extern` block", ) .emit(); @@ -201,7 +200,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { ); let filename = &tcx.sess.local_crate_source_file; let note = if !visitor.non_main_fns.is_empty() { - for &(_, span) in &visitor.non_main_fns { + for &span in &visitor.non_main_fns { err.span_note(span, "here is a function named `main`"); } err.note("you have one or more functions named `main` not defined at the crate level"); diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 0e60ca9f900..56755d68686 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -6,6 +6,7 @@ use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{HirId, ItemLocalId}; use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; pub fn check_crate(tcx: TyCtxt<'_>) { @@ -57,22 +58,22 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> { impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id(), |this| intravisit::walk_item(this, i)); + inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i)); } fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id(), |this| intravisit::walk_trait_item(this, i)); + inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i)); } fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id(), |this| intravisit::walk_impl_item(this, i)); + inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i)); } fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id(), |this| intravisit::walk_foreign_item(this, i)); + inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i)); } } @@ -83,9 +84,8 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { self.errors.lock().push(f()); } - fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) { + fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) { assert!(self.owner.is_none()); - let owner = self.hir_map.local_def_id(hir_id); self.owner = Some(owner); walk(self); @@ -140,10 +140,10 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { } impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { - type Map = Map<'hir>; + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { - intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) + fn nested_visit_map(&mut self) -> Self::Map { + self.hir_map } fn visit_id(&mut self, hir_id: HirId) { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d665c12f762..6cf1aa480d2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -95,12 +95,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_param(self, param) } - type Map = Map<'v>; - - fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> { - panic!("visit_nested_xxx must be manually implemented in this visitor") - } - fn visit_nested_item(&mut self, id: hir::ItemId) { let nested_item = self.krate.unwrap().item(id); self.visit_item(nested_item) @@ -338,9 +332,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { - self.record("AssocTyConstraint", Id::None, constraint); - ast_visit::walk_assoc_ty_constraint(self, constraint) + fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) { + self.record("AssocConstraint", Id::None, constraint); + ast_visit::walk_assoc_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 008b856ebf2..1031ba01c1b 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -3,7 +3,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; use rustc_middle::ty::query::Providers; @@ -62,7 +62,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { ty } -impl ExprVisitor<'tcx> { +impl<'tcx> ExprVisitor<'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { self.tcx.fn_sig(def_id).abi() == RustIntrinsic && self.tcx.item_name(def_id) == sym::transmute @@ -294,9 +294,8 @@ impl ExprVisitor<'tcx> { // (!). In that case we still need the earlier check to verify that the // register class is usable at all. if let Some(feature) = feature { - let feat_sym = Symbol::intern(feature); - if !self.tcx.sess.target_features.contains(&feat_sym) - && !target_features.contains(&feat_sym) + if !self.tcx.sess.target_features.contains(&feature) + && !target_features.contains(&feature) { let msg = &format!("`{}` target feature is not enabled", feature); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); @@ -377,9 +376,8 @@ impl ExprVisitor<'tcx> { { match feature { Some(feature) => { - let feat_sym = Symbol::intern(feature); - if self.tcx.sess.target_features.contains(&feat_sym) - || attrs.target_features.contains(&feat_sym) + if self.tcx.sess.target_features.contains(&feature) + || attrs.target_features.contains(&feature) { missing_required_features.clear(); break; @@ -413,7 +411,11 @@ impl ExprVisitor<'tcx> { let msg = format!( "register class `{}` requires at least one of the following target features: {}", reg_class.name(), - features.join(", ") + features + .iter() + .map(|f| f.as_str()) + .intersperse(", ") + .collect::<String>(), ); self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); // register isn't enabled, don't do more checks @@ -487,13 +489,7 @@ impl ExprVisitor<'tcx> { } } -impl Visitor<'tcx> for ItemVisitor<'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - +impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> { fn visit_nested_body(&mut self, body_id: hir::BodyId) { let owner_def_id = self.tcx.hir().body_owner_def_id(body_id); let body = self.tcx.hir().body(body_id); @@ -504,13 +500,7 @@ impl Visitor<'tcx> for ItemVisitor<'tcx> { } } -impl Visitor<'tcx> for ExprVisitor<'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - +impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { hir::ExprKind::Path(ref qpath) => { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 388c33917c6..0c934ecc913 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -10,7 +10,6 @@ use crate::check_attr::target_from_impl_item; use crate::weak_lang_items; -use rustc_ast::Attribute; use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -28,7 +27,7 @@ struct LanguageItemCollector<'tcx> { tcx: TyCtxt<'tcx>, } -impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { +impl<'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { self.check_for_lang(Target::from_item(item), item.hir_id()); @@ -50,15 +49,14 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {} } -impl LanguageItemCollector<'tcx> { +impl<'tcx> LanguageItemCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { LanguageItemCollector { tcx, items: LanguageItems::new() } } fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { let attrs = self.tcx.hir().attrs(hir_id); - let check_name = |attr: &Attribute, sym| attr.has_name(sym); - if let Some((value, span)) = extract(check_name, &attrs) { + if let Some((value, span)) = extract(&attrs) { match ITEM_REFS.get(&value).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 558d8958b13..00e8eb5eb2b 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -20,7 +20,7 @@ struct LayoutTest<'tcx> { tcx: TyCtxt<'tcx>, } -impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { +impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match item.kind { ItemKind::TyAlias(..) @@ -42,7 +42,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } -impl LayoutTest<'tcx> { +impl<'tcx> LayoutTest<'tcx> { fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) { let tcx = self.tcx; let param_env = self.tcx.param_env(item_def_id); @@ -114,7 +114,7 @@ struct UnwrapLayoutCx<'tcx> { param_env: ParamEnv<'tcx>, } -impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> { +impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> { type LayoutOfResult = TyAndLayout<'tcx>; fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { @@ -127,19 +127,19 @@ impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> { } } -impl HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> { +impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } -impl HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> { +impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> { fn param_env(&self) -> ParamEnv<'tcx> { self.param_env } } -impl HasDataLayout for UnwrapLayoutCx<'tcx> { +impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> { fn data_layout(&self) -> &TargetDataLayout { self.tcx.data_layout() } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 4adec3c4f60..2075fee7171 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,9 +6,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] -#![feature(in_band_lifetimes)] -#![feature(format_args_capture)] -#![feature(iter_zip)] +#![feature(iter_intersperse)] +#![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(nll)] diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index ff8bd37238d..00445690f8f 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,10 +4,10 @@ // and `#[unstable (..)]`), but are not declared in one single location // (unlike lang features), which means we need to collect them instead. -use rustc_ast::{Attribute, MetaItem, MetaItemKind}; +use rustc_ast::{Attribute, MetaItemKind}; use rustc_errors::struct_span_err; -use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; -use rustc_middle::hir::map::Map; +use rustc_hir::intravisit::Visitor; +use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -23,7 +23,7 @@ pub struct LibFeatureCollector<'tcx> { lib_features: LibFeatures, } -impl LibFeatureCollector<'tcx> { +impl<'tcx> LibFeatureCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> { LibFeatureCollector { tcx, lib_features: new_lib_features() } } @@ -34,8 +34,8 @@ impl LibFeatureCollector<'tcx> { // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`, // `#[rustc_const_unstable (..)]`). if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { - let meta_item = attr.meta(); - if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item { + let meta_kind = attr.meta_kind(); + if let Some(MetaItemKind::List(ref metas)) = meta_kind { let mut feature = None; let mut since = None; for meta in metas { @@ -110,11 +110,11 @@ impl LibFeatureCollector<'tcx> { } } -impl Visitor<'tcx> for LibFeatureCollector<'tcx> { - type Map = Map<'tcx>; +impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { + type NestedFilter = nested_filter::All; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::All(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_attribute(&mut self, _: rustc_hir::HirId, attr: &'tcx Attribute) { @@ -124,12 +124,12 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> { } } -fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { +fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { let mut collector = LibFeatureCollector::new(tcx); tcx.hir().walk_attributes(&mut collector); collector.lib_features } pub fn provide(providers: &mut Providers) { - providers.get_lib_features = get_lib_features; + providers.lib_features = lib_features; } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 3d7a215754a..69cd1b4fed5 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -90,10 +90,10 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::vec::IndexVec; -use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; @@ -103,7 +103,6 @@ use rustc_span::Span; use std::collections::VecDeque; use std::io; use std::io::prelude::*; -use std::iter; use std::rc::Rc; mod rwu_table; @@ -198,7 +197,7 @@ struct IrMaps<'tcx> { lnks: IndexVec<LiveNode, LiveNodeKind>, } -impl IrMaps<'tcx> { +impl<'tcx> IrMaps<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> { IrMaps { tcx, @@ -317,10 +316,10 @@ impl IrMaps<'tcx> { } impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { - type Map = Map<'tcx>; + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { @@ -429,8 +428,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprKind::Let(ref pat, ..) => { - self.add_from_pat(pat); + hir::ExprKind::Let(let_expr) => { + self.add_from_pat(let_expr.pat); intravisit::walk_expr(self, expr); } @@ -470,7 +469,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::LlvmInlineAsm(..) | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err @@ -726,7 +724,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue(_) => {} + ty::UpvarCapture::ByValue => {} } } } @@ -856,9 +854,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }) } - hir::ExprKind::Let(ref pat, ref scrutinee, _) => { - let succ = self.propagate_through_expr(scrutinee, succ); - self.define_bindings_in_pat(pat, succ) + hir::ExprKind::Let(let_expr) => { + let succ = self.propagate_through_expr(let_expr.init, succ); + self.define_bindings_in_pat(let_expr.pat, succ) } // Note that labels have been resolved, so we don't need to look @@ -1091,26 +1089,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { succ } - hir::ExprKind::LlvmInlineAsm(ref asm) => { - let ia = &asm.inner; - let outputs = asm.outputs_exprs; - let inputs = asm.inputs_exprs; - let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| { - // see comment on places - // in propagate_through_place_components() - if o.is_indirect { - self.propagate_through_expr(output, succ) - } else { - let acc = if o.is_rw { ACC_WRITE | ACC_READ } else { ACC_WRITE }; - let succ = self.write_place(output, succ, acc); - self.propagate_through_place_components(output, succ) - } - }); - - // Inputs are executed first. Propagate last because of rev order - self.propagate_through_exprs(inputs, succ) - } - hir::ExprKind::Lit(..) | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err @@ -1327,12 +1305,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Checking for error conditions impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| { if local.init.is_some() { @@ -1387,22 +1359,8 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { } } - hir::ExprKind::LlvmInlineAsm(ref asm) => { - for input in asm.inputs_exprs { - this.visit_expr(input); - } - - // Output operands must be places - for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) { - if !o.is_indirect { - this.check_place(output); - } - this.visit_expr(output); - } - } - - hir::ExprKind::Let(ref pat, ..) => { - this.check_unused_vars_in_pat(pat, None, |_, _, _, _| {}); + hir::ExprKind::Let(let_expr) => { + this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {}); } // no correctness conditions related to liveness @@ -1464,7 +1422,7 @@ impl<'tcx> Liveness<'_, 'tcx> { if name == kw::Empty { return None; } - let name: &str = &name.as_str(); + let name = name.as_str(); if name.as_bytes()[0] == b'_' { return None; } @@ -1481,7 +1439,7 @@ impl<'tcx> Liveness<'_, 'tcx> { for (&var_hir_id, min_capture_list) in closure_min_captures { for captured_place in min_capture_list { match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue(_) => {} + ty::UpvarCapture::ByValue => {} ty::UpvarCapture::ByRef(..) => continue, }; let span = captured_place.get_capture_kind_span(self.ir.tcx); diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 4bfac1b7298..02b09daf0a4 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -3,9 +3,10 @@ use Context::*; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -41,10 +42,10 @@ pub(crate) fn provide(providers: &mut Providers) { } impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { - type Map = Map<'hir>; + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.hir_map) + fn nested_visit_map(&mut self) -> Self::Map { + self.hir_map } fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d3ecd18a93c..00a93ccc9aa 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,14 +1,14 @@ //! Checks validity of naked functions. use rustc_ast::{Attribute, InlineAsmOptions}; +use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; -use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -29,15 +29,9 @@ struct CheckNakedFunctions<'tcx> { } impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { - type Map = ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_fn( &mut self, - fk: FnKind<'v>, + fk: FnKind<'_>, _fd: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, span: Span, @@ -70,18 +64,16 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { check_abi(self.tcx, hir_id, fn_header.abi, ident_span); check_no_patterns(self.tcx, body.params); check_no_parameters_use(self.tcx, body); - check_asm(self.tcx, hir_id, body, span); - check_inline(self.tcx, hir_id, attrs); + check_asm(self.tcx, body, span); + check_inline(self.tcx, attrs); } } } /// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) { +fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) { for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) { - tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| { - lint.build("naked functions cannot be inlined").emit(); - }); + tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit(); } } @@ -129,12 +121,6 @@ struct CheckParameters<'tcx> { } impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { - type Map = ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Path(hir::QPath::Resolved( _, @@ -158,31 +144,31 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { } /// Checks that function body contains a single inline assembly block. -fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) { +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) { let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; this.visit_body(body); if let [(ItemKind::Asm, _)] = this.items[..] { // Ok. } else { - tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| { - let mut diag = lint.build("naked functions must contain a single asm block"); - let mut has_asm = false; - for &(kind, span) in &this.items { - match kind { - ItemKind::Asm if has_asm => { - diag.span_label( - span, - "multiple asm blocks are unsupported in naked functions", - ); - } - ItemKind::Asm => has_asm = true, - ItemKind::NonAsm => { - diag.span_label(span, "non-asm is unsupported in naked functions"); - } + let mut diag = struct_span_err!( + tcx.sess, + fn_span, + E0787, + "naked functions must contain a single asm block" + ); + let mut has_asm = false; + for &(kind, span) in &this.items { + match kind { + ItemKind::Asm if has_asm => { + diag.span_label(span, "multiple asm blocks are unsupported in naked functions"); + } + ItemKind::Asm => has_asm = true, + ItemKind::NonAsm => { + diag.span_label(span, "non-asm is unsupported in naked functions"); } } - diag.emit(); - }); + } + diag.emit(); } } @@ -233,23 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { ExprKind::InlineAsm(ref asm) => { self.items.push((ItemKind::Asm, span)); - self.check_inline_asm(expr.hir_id, asm, span); - } - - ExprKind::LlvmInlineAsm(..) => { - self.items.push((ItemKind::Asm, span)); - self.tcx.struct_span_lint_hir( - UNSUPPORTED_NAKED_FUNCTIONS, - expr.hir_id, - span, - |lint| { - lint.build( - "the LLVM-style inline assembly is unsupported in naked functions", - ) - .help("use the new asm! syntax specified in RFC 2873") - .emit(); - }, - ); + self.check_inline_asm(asm, span); } ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => { @@ -258,7 +228,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } } - fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { + fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { let unsupported_operands: Vec<Span> = asm .operands .iter() @@ -271,18 +241,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> { }) .collect(); if !unsupported_operands.is_empty() { - self.tcx.struct_span_lint_hir( - UNSUPPORTED_NAKED_FUNCTIONS, - hir_id, + struct_span_err!( + self.tcx.sess, unsupported_operands, - |lint| { - lint.build("only `const` and `sym` operands are supported in naked functions") - .emit(); - }, - ); + E0787, + "only `const` and `sym` operands are supported in naked functions", + ) + .emit(); } let unsupported_options: Vec<&'static str> = [ + (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"), (InlineAsmOptions::NOMEM, "`nomem`"), (InlineAsmOptions::NOSTACK, "`nostack`"), (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"), @@ -294,30 +263,29 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .collect(); if !unsupported_options.is_empty() { - self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { - lint.build(&format!( - "asm options unsupported in naked functions: {}", - unsupported_options.join(", ") - )) - .emit(); - }); + struct_span_err!( + self.tcx.sess, + span, + E0787, + "asm options unsupported in naked functions: {}", + unsupported_options.join(", ") + ) + .emit(); } if !asm.options.contains(InlineAsmOptions::NORETURN) { - self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { - lint.build("asm in naked functions must use `noreturn` option").emit(); - }); + struct_span_err!( + self.tcx.sess, + span, + E0787, + "asm in naked functions must use `noreturn` option" + ) + .emit(); } } } impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { - type Map = ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { match stmt.kind { StmtKind::Item(..) => {} diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index bd1e9520ee9..6cd9dc23285 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi; // Returns true if the given item must be inlined because it may be // monomorphized or it was marked with `#[inline]`. This will only return // true for functions. -fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool { +fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool { if attrs.requests_inline() { return true; } @@ -52,7 +52,7 @@ fn method_might_be_inlined( return true; } } - match tcx.hir().find(tcx.hir().local_def_id_to_hir_id(impl_src)) { + match tcx.hir().find_by_def_id(impl_src) { Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs), Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"), } @@ -74,12 +74,6 @@ struct ReachableContext<'tcx> { } impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_nested_body(&mut self, body: hir::BodyId) { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); @@ -140,14 +134,11 @@ impl<'tcx> ReachableContext<'tcx> { // Returns true if the given def ID represents a local item that is // eligible for inlining and false otherwise. fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool { - let hir_id = match def_id.as_local() { - Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id), - None => { - return false; - } + let Some(def_id) = def_id.as_local() else { + return false; }; - match self.tcx.hir().find(hir_id) { + match self.tcx.hir().find_by_def_id(def_id) { Some(Node::Item(item)) => match item.kind { hir::ItemKind::Fn(..) => { item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)) @@ -169,12 +160,12 @@ impl<'tcx> ReachableContext<'tcx> { if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() { true } else { - let impl_did = self.tcx.hir().get_parent_did(hir_id); + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let impl_did = self.tcx.hir().get_parent_item(hir_id); // Check the impl. If the generics on the self // type of the impl require inlining, this method // does too. - let impl_hir_id = self.tcx.hir().local_def_id_to_hir_id(impl_did); - match self.tcx.hir().expect_item(impl_hir_id).kind { + match self.tcx.hir().expect_item(impl_did).kind { hir::ItemKind::Impl { .. } => { let generics = self.tcx.generics_of(impl_did); generics.requires_monomorphization(self.tcx) @@ -199,9 +190,7 @@ impl<'tcx> ReachableContext<'tcx> { continue; } - if let Some(ref item) = - self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(search_item)) - { + if let Some(ref item) = self.tcx.hir().find_by_def_id(search_item) { self.propagate_node(item, search_item); } } diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 5fc8e230d72..fdf93e58932 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -10,8 +10,8 @@ use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Block, Expr, Local, Node, Pat, PatKind, Stmt}; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt}; use rustc_index::vec::Idx; use rustc_middle::middle::region::*; use rustc_middle::ty::query::Providers; @@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // properly, we can't miss any types. match expr.kind { - // Manually recurse over closures, because they are the only + // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(.., body, _, _) => { + hir::ExprKind::Closure(.., body, _, _) + | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } @@ -365,7 +366,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h let target_scopes = visitor.fixup_scopes.drain(start_point..); for scope in target_scopes { - let mut yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap(); + let mut yield_data = + visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap(); let count = yield_data.expr_and_pat_count; let span = yield_data.span; @@ -420,12 +422,21 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // Mark this expr's scope and all parent scopes as containing `yield`. let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node }; loop { - let data = YieldData { - span: expr.span, - expr_and_pat_count: visitor.expr_and_pat_count, - source: *source, + let span = match expr.kind { + hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => { + expr.span.shrink_to_hi().to(expr.span) + } + _ => expr.span, }; - visitor.scope_tree.yield_in_scope.insert(scope, data); + let data = + YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source }; + match visitor.scope_tree.yield_in_scope.get_mut(&scope) { + Some(yields) => yields.push(data), + None => { + visitor.scope_tree.yield_in_scope.insert(scope, vec![data]); + } + } + if visitor.pessimistic_yield { debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope); visitor.fixup_scopes.push(scope); @@ -717,12 +728,6 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_block(&mut self, b: &'tcx Block<'tcx>) { resolve_block(self, b); } @@ -817,9 +822,9 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { } fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { - let closure_base_def_id = tcx.closure_base_def_id(def_id); - if closure_base_def_id != def_id { - return tcx.region_scope_tree(closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.region_scope_tree(typeck_root_def_id); } let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); @@ -836,19 +841,7 @@ fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { let body = tcx.hir().body(body_id); visitor.scope_tree.root_body = Some(body.value.hir_id); - - // If the item is an associated const or a method, - // record its impl/trait parent, as it can also have - // lifetime parameters free in this body. - match tcx.hir().get(id) { - Node::ImplItem(_) | Node::TraitItem(_) => { - visitor.scope_tree.root_parent = Some(tcx.hir().get_parent_item(id)); - } - _ => {} - } - visitor.visit_body(body); - visitor.scope_tree } else { ScopeTree::default() diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 8c9f04bef13..3521b6fc169 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -9,9 +9,9 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::hir_id::CRATE_HIR_ID; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant}; -use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; use rustc_middle::ty::{self, query::Providers, TyCtxt}; @@ -378,10 +378,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - type Map = Map<'tcx>; + type NestedFilter = nested_filter::All; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::All(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { @@ -593,10 +593,10 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { - type Map = Map<'tcx>; + type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { @@ -629,7 +629,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id())); + let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.def_id, ii.span); } @@ -655,7 +655,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { // stable (assuming they have not inherited instability from their parent). } -fn stability_index(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> { +fn stability_index<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api; let mut staged_api = FxHashMap::default(); @@ -737,14 +737,14 @@ struct Checker<'tcx> { tcx: TyCtxt<'tcx>, } -impl Visitor<'tcx> for Checker<'tcx> { - type Map = Map<'tcx>; +impl<'tcx> Visitor<'tcx> for Checker<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { @@ -794,19 +794,12 @@ impl Visitor<'tcx> for Checker<'tcx> { } } - if let Res::Def(DefKind::Trait, trait_did) = t.path.res { - for impl_item_ref in items { - let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - let trait_item_def_id = self - .tcx - .associated_items(trait_did) - .filter_by_name_unhygienic(impl_item.ident.name) - .next() - .map(|item| item.def_id); - if let Some(def_id) = trait_item_def_id { - // Pass `None` to skip deprecation warnings. - self.tcx.check_stability(def_id, None, impl_item.span, None); - } + for impl_item_ref in items { + let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id); + + if let Some(def_id) = impl_item.trait_item_def_id { + // Pass `None` to skip deprecation warnings. + self.tcx.check_stability(def_id, None, impl_item_ref.span, None); } } } @@ -866,13 +859,7 @@ struct CheckTraitImplStable<'tcx> { fully_stable: bool, } -impl Visitor<'tcx> for CheckTraitImplStable<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - +impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { if let Some(stab) = self.tcx.lookup_stability(def_id) { @@ -970,7 +957,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // We always collect the lib features declared in the current crate, even if there are // no unknown features, because the collection also does feature attribute validation. - let local_defined_features = tcx.lib_features().to_vec(); + let local_defined_features = tcx.lib_features(()).to_vec(); if !remaining_lib_features.is_empty() { check_features(&mut remaining_lib_features, &local_defined_features); diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index 91b8ae07637..25fe8e45825 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, HirId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -42,13 +42,7 @@ struct LocalCollector { locals: FxHashSet<HirId>, } -impl Visitor<'tcx> for LocalCollector { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - +impl<'tcx> Visitor<'tcx> for LocalCollector { fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.locals.insert(hir_id); @@ -71,13 +65,7 @@ impl CaptureCollector<'_, '_> { } } -impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - +impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { if let Res::Local(var_id) = path.res { self.visit_local_use(var_id, path.span); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index c6c32e69aab..6b73c950119 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,10 +1,9 @@ //! Validity checking for weak lang items -use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::required; @@ -67,10 +66,16 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); - tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler"); + tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler"); } } else { - tcx.sess.err(&format!("language item required, but not found: `{}`", name)); + tcx + .sess + .diagnostic() + .struct_err(&format!("language item required, but not found: `{}`", name)) + .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name)) + .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name)) + .emit(); } } } @@ -90,16 +95,9 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { - type Map = intravisit::ErasedMap<'v>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } - fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) { - let check_name = |attr: &Attribute, sym| attr.has_name(sym); let attrs = self.tcx.hir().attrs(i.hir_id()); - if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) { + if let Some((lang_item, _)) = lang_items::extract(attrs) { self.register(lang_item, i.span); } intravisit::walk_foreign_item(self, i) | 
