Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce tcx.get_diagnostic_name #89534

Merged
merged 3 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions compiler/rustc_hir/src/diagnostic_items.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_span::Symbol;

#[derive(Debug, Default)]
pub struct DiagnosticItems {
pub id_to_name: FxHashMap<DefId, Symbol>,
pub name_to_id: FxHashMap<Symbol, DefId>,
}

impl<CTX: crate::HashStableContext> HashStable<CTX> for DiagnosticItems {
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.name_to_id.hash_stable(ctx, hasher);
}
}
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod arena;
pub mod def;
pub mod def_path_hash_map;
pub mod definitions;
pub mod diagnostic_items;
pub use rustc_span::def_id;
mod hir;
pub mod hir_id;
Expand Down
28 changes: 13 additions & 15 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2478,14 +2478,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
// Find calls to `mem::{uninitialized,zeroed}` methods.
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;

if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
return Some(InitKind::Zeroed);
} else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) {
return Some(InitKind::Uninit);
} else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0])
{
return Some(InitKind::Zeroed);
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
_ => {}
}
}
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
Expand All @@ -2497,11 +2494,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;

if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
return Some(InitKind::Zeroed);
} else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
return Some(InitKind::Uninit);
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
_ => {}
}
}
}
Expand Down Expand Up @@ -3091,8 +3087,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
rustc_hir::ExprKind::Call(ref path, _) => {
if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
|| cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
return matches!(
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_null | sym::ptr_null_mut)
);
}
}
}
Expand Down
31 changes: 16 additions & 15 deletions compiler/rustc_lint/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
// don't lint imports, only actual usages
return;
}
let replace = if cx.tcx.is_diagnostic_item(sym::HashMap, def_id) {
"FxHashMap"
} else if cx.tcx.is_diagnostic_item(sym::HashSet, def_id) {
"FxHashSet"
} else {
return;
let replace = match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::HashMap) => "FxHashMap",
Some(sym::HashSet) => "FxHashSet",
_ => return,
};
cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
let msg = format!(
Expand Down Expand Up @@ -174,26 +172,29 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
if let TyKind::Path(qpath) = &ty.kind {
if let QPath::Resolved(_, path) = qpath {
match path.res {
Res::Def(_, did) => {
if cx.tcx.is_diagnostic_item(sym::Ty, did) {
return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
} else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
Res::Def(_, def_id) => {
if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
{
return Some(format!(
"{}{}",
name,
gen_args(path.segments.last().unwrap())
));
}
}
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
Res::SelfTy(None, Some((did, _))) => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) {
if let Some(name @ (sym::Ty | sym::TyCtxt)) =
cx.tcx.get_diagnostic_name(adt.did)
{
// NOTE: This path is currently unreachable as `Ty<'tcx>` is
// defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
// is not actually allowed.
//
// I(@lcnr) still kept this branch in so we don't miss this
// if we ever change it in the future.
return Some(format!("Ty<{}>", substs[0]));
} else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) {
return Some(format!("TyCtxt<{}>", substs[0]));
return Some(format!("{}<{}>", name, substs[0]));
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
|| Some(def_id) == cx.tcx.lang_items().panic_str()
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
|| cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
{
if matches!(
cx.tcx.get_diagnostic_name(id),
Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
) {
check_panic(cx, f, arg);
}
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_lint/src/noop_method_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
// Check that we're dealing with a trait method for one of the traits we care about.
Some(trait_id)
if [sym::Clone, sym::Deref, sym::Borrow]
.iter()
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
if matches!(
cx.tcx.get_diagnostic_name(trait_id),
Some(sym::Borrow | sym::Clone | sym::Deref)
) =>
{
(trait_id, did)
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1541,8 +1541,7 @@ impl InvalidAtomicOrdering {
if let ExprKind::Call(ref func, ref args) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::fence, def_id) ||
cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id);
if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence));
if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);
Expand Down
16 changes: 12 additions & 4 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::lang_items;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::hir::exports::Export;
Expand Down Expand Up @@ -1052,16 +1053,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}

/// Iterates over the diagnostic items in the given crate.
fn get_diagnostic_items(&self) -> FxHashMap<Symbol, DefId> {
fn get_diagnostic_items(&self) -> DiagnosticItems {
if self.root.is_proc_macro_crate() {
// Proc macro crates do not export any diagnostic-items to the target.
Default::default()
} else {
self.root
let mut id_to_name = FxHashMap::default();
let name_to_id = self
.root
.diagnostic_items
.decode(self)
.map(|(name, def_index)| (name, self.local_def_id(def_index)))
.collect()
.map(|(name, def_index)| {
let id = self.local_def_id(def_index);
id_to_name.insert(id, name);
(name, id)
})
.collect();
DiagnosticItems { id_to_name, name_to_id }
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,7 @@ impl EncodeContext<'a, 'tcx> {
fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
empty_proc_macro!(self);
let tcx = self.tcx;
let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE);
let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ rustc_queries! {
}

/// Returns all diagnostic items defined in all crates.
query all_diagnostic_items(_: ()) -> FxHashMap<Symbol, DefId> {
query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
storage(ArenaCacheSelector<'tcx>)
eval_always
desc { "calculating the diagnostic items map" }
Expand All @@ -1454,7 +1454,7 @@ rustc_queries! {
}

/// Returns the diagnostic items defined in a crate.
query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating the diagnostic items map in a crate" }
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,12 +1232,17 @@ impl<'tcx> TyCtxt<'tcx> {
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
self.all_diagnostic_items(()).get(&name).copied()
self.all_diagnostic_items(()).name_to_id.get(&name).copied()
}

/// Obtain the diagnostic item's name
pub fn get_diagnostic_name(self, id: DefId) -> Option<Symbol> {
self.diagnostic_items(id.krate).id_to_name.get(&id).copied()
}

/// Check whether the diagnostic item with the given `name` has the given `DefId`.
pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool {
self.diagnostic_items(did.krate).get(&name) == Some(&did)
self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did)
}

pub fn stability(self) -> &'tcx stability::Index<'tcx> {
Expand Down
34 changes: 14 additions & 20 deletions compiler/rustc_passes/src/diagnostic_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
//! * Compiler internal types like `Ty` and `TyCtxt`

use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};

struct DiagnosticItemCollector<'tcx> {
// items from this crate
items: FxHashMap<Symbol, DefId>,
tcx: TyCtxt<'tcx>,
diagnostic_items: DiagnosticItems,
}

impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
Expand All @@ -44,27 +43,22 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {

impl<'tcx> DiagnosticItemCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
DiagnosticItemCollector { tcx, items: Default::default() }
DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
}

fn observe_item(&mut self, def_id: LocalDefId) {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let attrs = self.tcx.hir().attrs(hir_id);
if let Some(name) = extract(attrs) {
// insert into our table
collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
}
}
}

fn collect_item(
tcx: TyCtxt<'_>,
items: &mut FxHashMap<Symbol, DefId>,
name: Symbol,
item_def_id: DefId,
) {
// Check for duplicates.
if let Some(original_def_id) = items.insert(name, item_def_id) {
fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) {
items.id_to_name.insert(item_def_id, name);
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
if original_def_id != item_def_id {
let mut err = match tcx.hir().span_if_local(item_def_id) {
Some(span) => tcx.sess.struct_span_err(
Expand Down Expand Up @@ -98,7 +92,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
}

/// Traverse and collect the diagnostic items in the current
fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol, DefId> {
fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems {
assert_eq!(cnum, LOCAL_CRATE);

// Initialize the collector.
Expand All @@ -107,22 +101,22 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol
// Collect diagnostic items in this crate.
tcx.hir().visit_all_item_likes(&mut collector);

collector.items
collector.diagnostic_items
}

/// Traverse and collect all the diagnostic items in all crates.
fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap<Symbol, DefId> {
fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems {
// Initialize the collector.
let mut collector = FxHashMap::default();
let mut items = DiagnosticItems::default();

// Collect diagnostic items in other crates.
for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) {
for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() {
collect_item(tcx, &mut collector, name, def_id);
for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id {
collect_item(tcx, &mut items, name, def_id);
}
}

collector
items
}

pub fn provide(providers: &mut Providers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1636,12 +1636,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {

// Special case the primary error message when send or sync is the trait that was
// not implemented.
let is_send = self.tcx.is_diagnostic_item(sym::Send, trait_ref.def_id);
let is_sync = self.tcx.is_diagnostic_item(sym::Sync, trait_ref.def_id);
let hir = self.tcx.hir();
let trait_explanation = if is_send || is_sync {
let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
self.tcx.get_diagnostic_name(trait_ref.def_id)
{
let (trait_name, trait_verb) =
if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };

err.clear_code();
err.set_primary_message(format!(
Expand Down
Loading