Add support for a new attribute #[debugger_visualizer] to support embedding debugger visualizers into a generated PDB.
Cleanup `DebuggerVisualizerFile` type and other minor cleanup of queries. Merge the queries for debugger visualizers into a single query. Revert move of `resolve_path` to `rustc_builtin_macros`. Update dependencies in Cargo.toml for `rustc_passes`. Respond to PR comments. Load visualizer files into opaque bytes `Vec<u8>`. Debugger visualizers for dynamically linked crates should not be embedded in the current crate. Update the unstable book with the new feature. Add the tracking issue for the debugger_visualizer feature. Respond to PR comments and minor cleanups.
This commit is contained in:
parent
e1df625306
commit
175a4eab84
29 changed files with 554 additions and 76 deletions
|
|
@ -9,6 +9,7 @@ rustc_middle = { path = "../rustc_middle" }
|
|||
rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_expand = { path = "../rustc_expand" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ impl CheckAttrVisitor<'_> {
|
|||
sym::allow_internal_unstable => {
|
||||
self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
|
||||
}
|
||||
sym::debugger_visualizer => self.check_debugger_visualizer(&attr, target),
|
||||
sym::rustc_allow_const_fn_unstable => {
|
||||
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
|
||||
}
|
||||
|
|
@ -1860,6 +1861,65 @@ impl CheckAttrVisitor<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
|
||||
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
|
||||
match target {
|
||||
Target::Mod => {}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "attribute should be applied to a module")
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let hints = match attr.meta_item_list() {
|
||||
Some(meta_item_list) => meta_item_list,
|
||||
None => {
|
||||
self.emit_debugger_visualizer_err(attr);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let hint = match hints.len() {
|
||||
1 => &hints[0],
|
||||
_ => {
|
||||
self.emit_debugger_visualizer_err(attr);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if !hint.has_name(sym::natvis_file) {
|
||||
self.emit_debugger_visualizer_err(attr);
|
||||
return false;
|
||||
}
|
||||
|
||||
let meta_item = match hint.meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
None => {
|
||||
self.emit_debugger_visualizer_err(attr);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(_)) => true,
|
||||
(_, _) => {
|
||||
self.emit_debugger_visualizer_err(attr);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_debugger_visualizer_err(&self, attr: &Attribute) {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "invalid argument")
|
||||
.note(r#"expected: `natvis_file = "..."`"#)
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
||||
/// (Allows proc_macro functions)
|
||||
fn check_rustc_allow_const_fn_unstable(
|
||||
|
|
|
|||
137
compiler/rustc_passes/src/debugger_visualizer.rs
Normal file
137
compiler/rustc_passes/src/debugger_visualizer.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
//! Detecting usage of the #[debugger_visualizer] attribute.
|
||||
|
||||
use hir::CRATE_HIR_ID;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::resolve_path;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{HirId, Target};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
struct DebuggerVisualizerCollector<'tcx> {
|
||||
debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
let target = Target::from_item(item);
|
||||
match target {
|
||||
Target::Mod => {
|
||||
self.check_for_debugger_visualizer(item.hir_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
|
||||
}
|
||||
|
||||
impl<'tcx> DebuggerVisualizerCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
|
||||
DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
|
||||
}
|
||||
|
||||
fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let meta_item = match list.len() {
|
||||
1 => match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(value)) => {
|
||||
match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
(_, _) => continue,
|
||||
};
|
||||
|
||||
if file.is_file() {
|
||||
let contents = match std::fs::read(&file) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!(
|
||||
"Unable to read contents of file `{}`. {}",
|
||||
file.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
|
||||
Arc::from(contents),
|
||||
DebuggerVisualizerType::Natvis,
|
||||
));
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!("{} is not a valid file", file.display()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverses and collects the debugger visualizers for a specific crate.
|
||||
fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<DebuggerVisualizerFile> {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
// Initialize the collector.
|
||||
let mut collector = DebuggerVisualizerCollector::new(tcx);
|
||||
|
||||
// Collect debugger visualizers in this crate.
|
||||
tcx.hir().visit_all_item_likes(&mut collector);
|
||||
|
||||
// Collect debugger visualizers on the crate attributes.
|
||||
collector.check_for_debugger_visualizer(CRATE_HIR_ID);
|
||||
|
||||
// Extract out the found debugger_visualizer items.
|
||||
let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
|
||||
|
||||
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
||||
|
||||
// Sort the visualizers so we always get a deterministic query result.
|
||||
visualizers.sort();
|
||||
visualizers
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
providers.debugger_visualizers = debugger_visualizers;
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ use rustc_middle::ty::query::Providers;
|
|||
mod check_attr;
|
||||
mod check_const;
|
||||
pub mod dead;
|
||||
mod debugger_visualizer;
|
||||
mod diagnostic_items;
|
||||
pub mod entry;
|
||||
pub mod hir_id_validator;
|
||||
|
|
@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
check_attr::provide(providers);
|
||||
check_const::provide(providers);
|
||||
dead::provide(providers);
|
||||
debugger_visualizer::provide(providers);
|
||||
diagnostic_items::provide(providers);
|
||||
entry::provide(providers);
|
||||
lang_items::provide(providers);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue