Skip to content

Commit 7f01893

Browse files
Fix dependency tracking for debugger visualizers
1 parent 72b2716 commit 7f01893

File tree

16 files changed

+133
-117
lines changed

16 files changed

+133
-117
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
486486
files.push(normalize_path(profile_sample.as_path().to_path_buf()));
487487
}
488488

489+
// Debugger visualizer files
490+
for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
491+
files.push(normalize_path(debugger_visualizer.path.clone().unwrap()));
492+
}
493+
489494
if sess.binary_dep_depinfo() {
490495
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
491496
if backend.contains('.') {
@@ -567,6 +572,12 @@ fn resolver_for_lowering<'tcx>(
567572
// Make sure we don't mutate the cstore from here on.
568573
tcx.untracked().cstore.leak();
569574

575+
{
576+
let debugger_visualizers = rustc_passes::debugger_visualizer::collect(tcx.sess, &krate);
577+
let feed = tcx.feed_local_crate();
578+
feed.debugger_visualizers(debugger_visualizers);
579+
}
580+
570581
let ty::ResolverOutputs {
571582
global_ctxt: untracked_resolutions,
572583
ast_lowering: untracked_resolver_for_lowering,

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18521852

18531853
fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
18541854
empty_proc_macro!(self);
1855-
self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
1855+
self.lazy_array(
1856+
self.tcx
1857+
.debugger_visualizers(LOCAL_CRATE)
1858+
.iter()
1859+
// Erase the path since it may contain privacy sensitive data
1860+
// that we don't want to end up in crate metadata.
1861+
// The path is only needed for the local crate because of
1862+
// `--emit dep-info`.
1863+
.map(DebuggerVisualizerFile::path_erased),
1864+
)
18561865
}
18571866

18581867
fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {

compiler/rustc_middle/src/hir/map/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_index::Idx;
1515
use rustc_middle::hir::nested_filter;
1616
use rustc_span::def_id::StableCrateId;
1717
use rustc_span::symbol::{kw, sym, Ident, Symbol};
18-
use rustc_span::Span;
18+
use rustc_span::{DebuggerVisualizerFile, Span};
1919
use rustc_target::spec::abi::Abi;
2020

2121
#[inline]
@@ -1165,11 +1165,21 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
11651165

11661166
source_file_names.sort_unstable();
11671167

1168+
let debugger_visualizers: Vec<_> = tcx
1169+
.debugger_visualizers(LOCAL_CRATE)
1170+
.iter()
1171+
// We ignore the path to the visualizer file since it's not going to be
1172+
// encoded in crate metadata and we already hash the full contents of
1173+
// the file.
1174+
.map(DebuggerVisualizerFile::path_erased)
1175+
.collect();
1176+
11681177
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
11691178
let mut stable_hasher = StableHasher::new();
11701179
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
11711180
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
11721181
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
1182+
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
11731183
if tcx.sess.opts.incremental_relative_spans() {
11741184
let definitions = tcx.definitions_untracked();
11751185
let mut owner_spans: Vec<_> = krate

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,7 @@ rustc_queries! {
17951795
arena_cache
17961796
desc { "looking up the debugger visualizers for this crate" }
17971797
separate_provide_extern
1798+
feedable
17981799
}
17991800
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
18001801
eval_always

compiler/rustc_passes/src/check_attr.rs

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::{errors, fluent_generated as fluent};
88
use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
11-
use rustc_expand::base::resolve_path;
1211
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
1312
use rustc_hir as hir;
1413
use rustc_hir::def_id::LocalDefId;
@@ -1916,6 +1915,7 @@ impl CheckAttrVisitor<'_> {
19161915

19171916
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
19181917
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
1918+
// FIXME: mention that other checks are done in the query provider
19191919
match target {
19201920
Target::Mod => {}
19211921
_ => {
@@ -1924,53 +1924,7 @@ impl CheckAttrVisitor<'_> {
19241924
}
19251925
}
19261926

1927-
let Some(hints) = attr.meta_item_list() else {
1928-
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
1929-
return false;
1930-
};
1931-
1932-
let hint = match hints.len() {
1933-
1 => &hints[0],
1934-
_ => {
1935-
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
1936-
return false;
1937-
}
1938-
};
1939-
1940-
let Some(meta_item) = hint.meta_item() else {
1941-
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
1942-
return false;
1943-
};
1944-
1945-
let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
1946-
(sym::natvis_file, Some(value)) => value,
1947-
(sym::gdb_script_file, Some(value)) => value,
1948-
(_, _) => {
1949-
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
1950-
return false;
1951-
}
1952-
};
1953-
1954-
let file =
1955-
match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
1956-
Ok(file) => file,
1957-
Err(mut err) => {
1958-
err.emit();
1959-
return false;
1960-
}
1961-
};
1962-
1963-
match std::fs::File::open(&file) {
1964-
Ok(_) => true,
1965-
Err(error) => {
1966-
self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable {
1967-
span: meta_item.span,
1968-
file: &file,
1969-
error,
1970-
});
1971-
false
1972-
}
1973-
}
1927+
true
19741928
}
19751929

19761930
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
Lines changed: 58 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,64 @@
11
//! Detecting usage of the `#[debugger_visualizer]` attribute.
22
3-
use hir::CRATE_HIR_ID;
4-
use rustc_data_structures::fx::FxHashSet;
3+
use rustc_ast::Attribute;
54
use rustc_data_structures::sync::Lrc;
65
use rustc_expand::base::resolve_path;
7-
use rustc_hir as hir;
8-
use rustc_hir::HirId;
9-
use rustc_middle::query::{LocalCrate, Providers};
10-
use rustc_middle::ty::TyCtxt;
6+
use rustc_session::Session;
117
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
128

13-
use crate::errors::DebugVisualizerUnreadable;
9+
use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
1410

15-
fn check_for_debugger_visualizer(
16-
tcx: TyCtxt<'_>,
17-
hir_id: HirId,
18-
debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
19-
) {
20-
let attrs = tcx.hir().attrs(hir_id);
21-
for attr in attrs {
11+
impl DebuggerVisualizerCollector<'_> {
12+
fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
2213
if attr.has_name(sym::debugger_visualizer) {
23-
let Some(list) = attr.meta_item_list() else {
24-
continue
14+
let Some(hints) = attr.meta_item_list() else {
15+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
16+
return;
2517
};
2618

27-
let meta_item = match list.len() {
28-
1 => match list[0].meta_item() {
29-
Some(meta_item) => meta_item,
30-
_ => continue,
31-
},
32-
_ => continue,
19+
let hint = if hints.len() == 1 {
20+
&hints[0]
21+
} else {
22+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
23+
return;
3324
};
3425

35-
let visualizer_type = match meta_item.name_or_empty() {
36-
sym::natvis_file => DebuggerVisualizerType::Natvis,
37-
sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
38-
_ => continue,
26+
let Some(meta_item) = hint.meta_item() else {
27+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
28+
return;
3929
};
4030

41-
let file = match meta_item.value_str() {
42-
Some(value) => {
43-
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
44-
Ok(file) => file,
45-
_ => continue,
31+
let (visualizer_type, visualizer_path) =
32+
match (meta_item.name_or_empty(), meta_item.value_str()) {
33+
(sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value),
34+
(sym::gdb_script_file, Some(value)) => {
35+
(DebuggerVisualizerType::GdbPrettyPrinter, value)
4636
}
47-
}
48-
None => continue,
49-
};
37+
(_, _) => {
38+
self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span });
39+
return;
40+
}
41+
};
42+
43+
let file =
44+
match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) {
45+
Ok(file) => file,
46+
Err(mut err) => {
47+
err.emit();
48+
return;
49+
}
50+
};
5051

5152
match std::fs::read(&file) {
5253
Ok(contents) => {
53-
debugger_visualizers
54-
.insert(DebuggerVisualizerFile::new(Lrc::from(contents), visualizer_type));
54+
self.visualizers.push(DebuggerVisualizerFile::new(
55+
Lrc::from(contents),
56+
visualizer_type,
57+
file,
58+
));
5559
}
5660
Err(error) => {
57-
tcx.sess.emit_err(DebugVisualizerUnreadable {
61+
self.sess.emit_err(DebugVisualizerUnreadable {
5862
span: meta_item.span,
5963
file: &file,
6064
error,
@@ -65,31 +69,25 @@ fn check_for_debugger_visualizer(
6569
}
6670
}
6771

68-
/// Traverses and collects the debugger visualizers for a specific crate.
69-
fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
70-
// Initialize the collector.
71-
let mut debugger_visualizers = FxHashSet::default();
72-
73-
// Collect debugger visualizers in this crate.
74-
tcx.hir().for_each_module(|id| {
75-
check_for_debugger_visualizer(
76-
tcx,
77-
tcx.hir().local_def_id_to_hir_id(id),
78-
&mut debugger_visualizers,
79-
)
80-
});
72+
struct DebuggerVisualizerCollector<'a> {
73+
sess: &'a Session,
74+
visualizers: Vec<DebuggerVisualizerFile>,
75+
}
8176

82-
// Collect debugger visualizers on the crate attributes.
83-
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
77+
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
78+
fn visit_attribute(&mut self, attr: &'ast Attribute) {
79+
self.check_for_debugger_visualizer(attr);
80+
rustc_ast::visit::walk_attribute(self, attr);
81+
}
82+
}
8483

85-
// Extract out the found debugger_visualizer items.
86-
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
84+
/// Traverses and collects the debugger visualizers for a specific crate.
85+
pub fn collect(sess: &Session, krate: &rustc_ast::ast::Crate) -> Vec<DebuggerVisualizerFile> {
86+
// Initialize the collector.
87+
let mut visitor = DebuggerVisualizerCollector { sess, visualizers: Vec::new() };
88+
rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate);
8789

8890
// Sort the visualizers so we always get a deterministic query result.
89-
visualizers.sort();
90-
visualizers
91-
}
92-
93-
pub fn provide(providers: &mut Providers) {
94-
providers.debugger_visualizers = debugger_visualizers;
91+
visitor.visualizers.sort_unstable();
92+
visitor.visualizers
9593
}

compiler/rustc_passes/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_middle::query::Providers;
2727
mod check_attr;
2828
mod check_const;
2929
pub mod dead;
30-
mod debugger_visualizer;
30+
pub mod debugger_visualizer;
3131
mod diagnostic_items;
3232
pub mod entry;
3333
mod errors;
@@ -50,7 +50,6 @@ pub fn provide(providers: &mut Providers) {
5050
check_attr::provide(providers);
5151
check_const::provide(providers);
5252
dead::provide(providers);
53-
debugger_visualizer::provide(providers);
5453
diagnostic_items::provide(providers);
5554
entry::provide(providers);
5655
lang_items::provide(providers);

compiler/rustc_span/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,11 +1272,21 @@ pub struct DebuggerVisualizerFile {
12721272
pub src: Lrc<[u8]>,
12731273
/// Indicates which visualizer type this targets.
12741274
pub visualizer_type: DebuggerVisualizerType,
1275+
// FIXME: Docs
1276+
pub path: Option<PathBuf>,
12751277
}
12761278

12771279
impl DebuggerVisualizerFile {
1278-
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
1279-
DebuggerVisualizerFile { src, visualizer_type }
1280+
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self {
1281+
DebuggerVisualizerFile { src, visualizer_type, path: Some(path) }
1282+
}
1283+
1284+
pub fn path_erased(&self) -> Self {
1285+
DebuggerVisualizerFile {
1286+
src: self.src.clone(),
1287+
visualizer_type: self.visualizer_type,
1288+
path: None,
1289+
}
12801290
}
12811291
}
12821292

src/tools/tidy/src/ui_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
3535
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
3636
"tests/ui/unused-crate-deps/test.mk", // why would you use make
3737
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
38+
"tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
3839
];
3940

4041
fn check_entries(tests_path: &Path, bad: &mut bool) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# ignore-windows-gnu
2+
3+
include ../tools.mk
4+
5+
all:
6+
$(RUSTC) --emit dep-info main.rs
7+
$(CGREP) "foo.py" < $(TMPDIR)/main.d
8+
$(CGREP) "my_visualizers/bar.py" < $(TMPDIR)/main.d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# empty
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![debugger_visualizer(gdb_script_file = "foo.py")]
2+
3+
fn main() {
4+
const _UNUSED: u32 = {
5+
mod inner {
6+
#![debugger_visualizer(gdb_script_file = "my_visualizers/bar.py")]
7+
pub const XYZ: u32 = 123;
8+
}
9+
10+
inner::XYZ + 1
11+
};
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# empty

tests/ui/invalid/foo.natvis.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- empty -->
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#[debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR attribute should be applied to a module
1+
#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module
22
fn main() {}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: attribute should be applied to a module
22
--> $DIR/invalid-debugger-visualizer-target.rs:1:1
33
|
4-
LL | #[debugger_visualizer(natvis_file = "../foo.natvis")]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

0 commit comments

Comments
 (0)