Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 17a6810

Browse files
committedMay 19, 2023
Auto merge of #111641 - michaelwoerister:debugger-visualizer-fixes, r=cjgillot
Fix dependency tracking for debugger visualizers This PR fixes dependency tracking for debugger visualizer files by changing the `debugger_visualizers` query to an `eval_always` query that scans the AST while it is still available. This way the set of visualizer files is already available when dep-info is emitted. Since the query is turned into an `eval_always` query, dependency tracking will now reliably detect changes to the visualizer script files themselves. TODO: - [x] perf.rlo - [x] Needs a bit more documentation in some places - [x] Needs regression test for the incr. comp. case Fixes #111226 Fixes #111227 Fixes #111295 r? `@wesleywiser` cc `@gibbyfree`
2 parents 2d17294 + 987655a commit 17a6810

File tree

27 files changed

+246
-145
lines changed

27 files changed

+246
-145
lines changed
 

‎compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ use rustc_errors::{
5858
use rustc_fluent_macro::fluent_messages;
5959
use rustc_hir as hir;
6060
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
61-
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
61+
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
6262
use rustc_hir::definitions::DefPathData;
6363
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
6464
use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -435,6 +435,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
435435
// Queries that borrow `resolver_for_lowering`.
436436
tcx.ensure_with_value().output_filenames(());
437437
tcx.ensure_with_value().early_lint_checks(());
438+
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
438439
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
439440

440441
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);

‎compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ use rustc_ast::attr;
99
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
1010
use rustc_codegen_ssa::traits::*;
1111
use rustc_hir::def_id::LOCAL_CRATE;
12-
use rustc_middle::bug;
12+
use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType};
1313
use rustc_session::config::{CrateType, DebugInfo};
1414
use rustc_span::symbol::sym;
15-
use rustc_span::DebuggerVisualizerType;
1615

1716
/// Inserts a side-effect free instruction sequence that makes sure that the
1817
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.

‎compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc;
99
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
1010
use rustc_metadata::find_native_static_library;
1111
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
12+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
1213
use rustc_middle::middle::dependency_format::Linkage;
1314
use rustc_middle::middle::exported_symbols::SymbolExportKind;
1415
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@@ -21,7 +22,6 @@ use rustc_session::utils::NativeLibKind;
2122
/// need out of the shared crate context before we get rid of it.
2223
use rustc_session::{filesearch, Session};
2324
use rustc_span::symbol::Symbol;
24-
use rustc_span::DebuggerVisualizerFile;
2525
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
2626
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
2727
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};

‎compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2323
use rustc_hir::lang_items::LangItem;
2424
use rustc_metadata::EncodedMetadata;
2525
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
26+
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
2627
use rustc_middle::middle::exported_symbols;
2728
use rustc_middle::middle::exported_symbols::SymbolExportKind;
2829
use rustc_middle::middle::lang_items;
@@ -35,7 +36,6 @@ use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
3536
use rustc_session::Session;
3637
use rustc_span::symbol::sym;
3738
use rustc_span::Symbol;
38-
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
3939
use rustc_target::abi::{Align, FIRST_VARIANT};
4040

4141
use std::collections::BTreeSet;

‎compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
2828
use rustc_fluent_macro::fluent_messages;
2929
use rustc_hir::def_id::CrateNum;
3030
use rustc_middle::dep_graph::WorkProduct;
31+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
3132
use rustc_middle::middle::dependency_format::Dependencies;
3233
use rustc_middle::middle::exported_symbols::SymbolExportKind;
3334
use rustc_middle::query::{ExternProviders, Providers};
@@ -38,7 +39,6 @@ use rustc_session::cstore::{self, CrateSource};
3839
use rustc_session::utils::NativeLibKind;
3940
use rustc_session::Session;
4041
use rustc_span::symbol::Symbol;
41-
use rustc_span::DebuggerVisualizerFile;
4242
use std::collections::BTreeSet;
4343
use std::io;
4444
use std::path::{Path, PathBuf};

‎compiler/rustc_interface/src/passes.rs

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

490+
// Debugger visualizer files
491+
for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
492+
files.push(normalize_path(debugger_visualizer.path.clone().unwrap()));
493+
}
494+
490495
if sess.binary_dep_depinfo() {
491496
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
492497
if backend.contains('.') {

‎compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
1919
use rustc_hir::diagnostic_items::DiagnosticItems;
2020
use rustc_index::{Idx, IndexVec};
2121
use rustc_middle::metadata::ModChild;
22+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2223
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2324
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
2425
use rustc_middle::ty::codec::TyDecoder;
@@ -958,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
958959
.decode((self, sess))
959960
}
960961

961-
fn get_debugger_visualizers(self) -> Vec<rustc_span::DebuggerVisualizerFile> {
962+
fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> {
962963
self.root.debugger_visualizers.decode(self).collect::<Vec<_>>()
963964
}
964965

‎compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_hir::definitions::DefPathData;
1919
use rustc_hir::intravisit::{self, Visitor};
2020
use rustc_hir::lang_items::LangItem;
2121
use rustc_middle::hir::nested_filter;
22+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2223
use rustc_middle::middle::dependency_format::Linkage;
2324
use rustc_middle::middle::exported_symbols::{
2425
metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
@@ -36,9 +37,7 @@ use rustc_session::config::{CrateType, OptLevel};
3637
use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
3738
use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
3839
use rustc_span::symbol::{sym, Symbol};
39-
use rustc_span::{
40-
self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
41-
};
40+
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
4241
use std::borrow::Borrow;
4342
use std::collections::hash_map::Entry;
4443
use std::hash::Hash;
@@ -1855,7 +1854,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18551854

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

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

‎compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::creader::CrateMetadataRef;
22
use decoder::Metadata;
33
use def_path_hash_map::DefPathHashMapRef;
44
use rustc_data_structures::fx::FxHashMap;
5+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
56
use table::TableBuilder;
67

78
use rustc_ast as ast;
@@ -245,7 +246,7 @@ pub(crate) struct CrateRoot {
245246
proc_macro_data: Option<ProcMacroData>,
246247

247248
tables: LazyTables,
248-
debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>,
249+
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
249250

250251
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
251252

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::hir::{ModuleItems, Owner};
2+
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
23
use crate::query::LocalCrate;
34
use crate::ty::TyCtxt;
45
use rustc_ast as ast;
@@ -1165,11 +1166,26 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
11651166

11661167
source_file_names.sort_unstable();
11671168

1169+
// We have to take care of debugger visualizers explicitly. The HIR (and
1170+
// thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but
1171+
// these attributes only store the file path to the visualizer file, not
1172+
// their content. Yet that content is exported into crate metadata, so any
1173+
// changes to it need to be reflected in the crate hash.
1174+
let debugger_visualizers: Vec<_> = tcx
1175+
.debugger_visualizers(LOCAL_CRATE)
1176+
.iter()
1177+
// We ignore the path to the visualizer file since it's not going to be
1178+
// encoded in crate metadata and we already hash the full contents of
1179+
// the file.
1180+
.map(DebuggerVisualizerFile::path_erased)
1181+
.collect();
1182+
11681183
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
11691184
let mut stable_hasher = StableHasher::new();
11701185
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
11711186
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
11721187
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
1188+
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
11731189
if tcx.sess.opts.incremental_relative_spans() {
11741190
let definitions = tcx.definitions_untracked();
11751191
let mut owner_spans: Vec<_> = krate
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use rustc_data_structures::sync::Lrc;
2+
use std::path::PathBuf;
3+
4+
#[derive(HashStable)]
5+
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
6+
pub enum DebuggerVisualizerType {
7+
Natvis,
8+
GdbPrettyPrinter,
9+
}
10+
11+
/// A single debugger visualizer file.
12+
#[derive(HashStable)]
13+
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
14+
pub struct DebuggerVisualizerFile {
15+
/// The complete debugger visualizer source.
16+
pub src: Lrc<[u8]>,
17+
/// Indicates which visualizer type this targets.
18+
pub visualizer_type: DebuggerVisualizerType,
19+
/// The file path to the visualizer file. This is used for reporting
20+
/// visualizer files in dep-info. Before it is written to crate metadata,
21+
/// the path is erased to `None`, so as not to emit potentially privacy
22+
/// sensitive data.
23+
pub path: Option<PathBuf>,
24+
}
25+
26+
impl DebuggerVisualizerFile {
27+
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self {
28+
DebuggerVisualizerFile { src, visualizer_type, path: Some(path) }
29+
}
30+
31+
pub fn path_erased(&self) -> Self {
32+
DebuggerVisualizerFile {
33+
src: self.src.clone(),
34+
visualizer_type: self.visualizer_type,
35+
path: None,
36+
}
37+
}
38+
}

‎compiler/rustc_middle/src/middle/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod codegen_fn_attrs;
2+
pub mod debugger_visualizer;
23
pub mod dependency_format;
34
pub mod exported_symbols;
45
pub mod lang_items;

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::infer::canonical::{self, Canonical};
1212
use crate::lint::LintExpectation;
1313
use crate::metadata::ModChild;
1414
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
15+
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
1516
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
1617
use crate::middle::lib_features::LibFeatures;
1718
use crate::middle::privacy::EffectiveVisibilities;
@@ -1784,12 +1785,18 @@ rustc_queries! {
17841785
desc { "looking at the source for a crate" }
17851786
separate_provide_extern
17861787
}
1788+
17871789
/// Returns the debugger visualizers defined for this crate.
1788-
query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
1790+
/// NOTE: This query has to be marked `eval_always` because it reads data
1791+
/// directly from disk that is not tracked anywhere else. I.e. it
1792+
/// represents a genuine input to the query system.
1793+
query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> {
17891794
arena_cache
17901795
desc { "looking up the debugger visualizers for this crate" }
17911796
separate_provide_extern
1797+
eval_always
17921798
}
1799+
17931800
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
17941801
eval_always
17951802
desc { "generating a postorder list of CrateNums" }

‎compiler/rustc_middle/src/ty/parameterized.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ trivially_parameterized_over_tcx! {
5656
std::string::String,
5757
crate::metadata::ModChild,
5858
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
59+
crate::middle::debugger_visualizer::DebuggerVisualizerFile,
5960
crate::middle::exported_symbols::SymbolExportInfo,
6061
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
6162
crate::mir::ConstQualifs,
@@ -91,7 +92,6 @@ trivially_parameterized_over_tcx! {
9192
rustc_session::cstore::ForeignModule,
9293
rustc_session::cstore::LinkagePreference,
9394
rustc_session::cstore::NativeLib,
94-
rustc_span::DebuggerVisualizerFile,
9595
rustc_span::ExpnData,
9696
rustc_span::ExpnHash,
9797
rustc_span::ExpnId,

‎compiler/rustc_passes/src/check_attr.rs

Lines changed: 5 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,10 @@ 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+
// Here we only check that the #[debugger_visualizer] attribute is attached
1919+
// to nothing other than a module. All other checks are done in the
1920+
// `debugger_visualizer` query where they need to be done for decoding
1921+
// anyway.
19191922
match target {
19201923
Target::Mod => {}
19211924
_ => {
@@ -1924,53 +1927,7 @@ impl CheckAttrVisitor<'_> {
19241927
}
19251928
}
19261929

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-
}
1930+
true
19741931
}
19751932

19761933
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.

‎compiler/rustc_passes/src/debugger_visualizer.rs

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,69 @@
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;
11-
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
6+
use rustc_middle::{
7+
middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType},
8+
query::{LocalCrate, Providers},
9+
ty::TyCtxt,
10+
};
11+
use rustc_session::Session;
12+
use rustc_span::sym;
1213

13-
use crate::errors::DebugVisualizerUnreadable;
14+
use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
1415

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 {
16+
impl DebuggerVisualizerCollector<'_> {
17+
fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
2218
if attr.has_name(sym::debugger_visualizer) {
23-
let Some(list) = attr.meta_item_list() else {
24-
continue
19+
let Some(hints) = attr.meta_item_list() else {
20+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
21+
return;
2522
};
2623

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,
24+
let hint = if hints.len() == 1 {
25+
&hints[0]
26+
} else {
27+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
28+
return;
3329
};
3430

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,
31+
let Some(meta_item) = hint.meta_item() else {
32+
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
33+
return;
3934
};
4035

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,
36+
let (visualizer_type, visualizer_path) =
37+
match (meta_item.name_or_empty(), meta_item.value_str()) {
38+
(sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value),
39+
(sym::gdb_script_file, Some(value)) => {
40+
(DebuggerVisualizerType::GdbPrettyPrinter, value)
4641
}
47-
}
48-
None => continue,
49-
};
42+
(_, _) => {
43+
self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span });
44+
return;
45+
}
46+
};
47+
48+
let file =
49+
match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) {
50+
Ok(file) => file,
51+
Err(mut err) => {
52+
err.emit();
53+
return;
54+
}
55+
};
5056

5157
match std::fs::read(&file) {
5258
Ok(contents) => {
53-
debugger_visualizers
54-
.insert(DebuggerVisualizerFile::new(Lrc::from(contents), visualizer_type));
59+
self.visualizers.push(DebuggerVisualizerFile::new(
60+
Lrc::from(contents),
61+
visualizer_type,
62+
file,
63+
));
5564
}
5665
Err(error) => {
57-
tcx.sess.emit_err(DebugVisualizerUnreadable {
66+
self.sess.emit_err(DebugVisualizerUnreadable {
5867
span: meta_item.span,
5968
file: &file,
6069
error,
@@ -65,29 +74,30 @@ fn check_for_debugger_visualizer(
6574
}
6675
}
6776

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();
77+
struct DebuggerVisualizerCollector<'a> {
78+
sess: &'a Session,
79+
visualizers: Vec<DebuggerVisualizerFile>,
80+
}
7281

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-
});
82+
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
83+
fn visit_attribute(&mut self, attr: &'ast Attribute) {
84+
self.check_for_debugger_visualizer(attr);
85+
rustc_ast::visit::walk_attribute(self, attr);
86+
}
87+
}
8188

82-
// Collect debugger visualizers on the crate attributes.
83-
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
89+
/// Traverses and collects the debugger visualizers for a specific crate.
90+
fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
91+
let resolver_and_krate = tcx.resolver_for_lowering(()).borrow();
92+
let krate = &*resolver_and_krate.1;
8493

85-
// Extract out the found debugger_visualizer items.
86-
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
94+
let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() };
95+
rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate);
8796

88-
// Sort the visualizers so we always get a deterministic query result.
89-
visualizers.sort();
90-
visualizers
97+
// We are collecting visualizers in AST-order, which is deterministic,
98+
// so we don't need to do any explicit sorting in order to get a
99+
// deterministic query result
100+
visitor.visualizers
91101
}
92102

93103
pub fn provide(providers: &mut Providers) {

‎compiler/rustc_span/src/lib.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,29 +1257,6 @@ impl SourceFileHash {
12571257
}
12581258
}
12591259

1260-
#[derive(HashStable_Generic)]
1261-
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1262-
pub enum DebuggerVisualizerType {
1263-
Natvis,
1264-
GdbPrettyPrinter,
1265-
}
1266-
1267-
/// A single debugger visualizer file.
1268-
#[derive(HashStable_Generic)]
1269-
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
1270-
pub struct DebuggerVisualizerFile {
1271-
/// The complete debugger visualizer source.
1272-
pub src: Lrc<[u8]>,
1273-
/// Indicates which visualizer type this targets.
1274-
pub visualizer_type: DebuggerVisualizerType,
1275-
}
1276-
1277-
impl DebuggerVisualizerFile {
1278-
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
1279-
DebuggerVisualizerFile { src, visualizer_type }
1280-
}
1281-
}
1282-
12831260
#[derive(Clone)]
12841261
pub enum SourceFileLines {
12851262
/// The source file lines, in decoded (random-access) form.

‎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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include ../tools.mk
2+
3+
# This test makes sure that files referenced via #[debugger_visualizer] are
4+
# included in `--emit dep-info` output.
5+
6+
all:
7+
$(RUSTC) --emit dep-info main.rs
8+
$(CGREP) "foo.py" < $(TMPDIR)/main.d
9+
$(CGREP) "my_visualizers/bar.natvis" < $(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(natvis_file = "my_visualizers/bar.natvis")]
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 -->
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
include ../tools.mk
2+
3+
# This test makes sure that changes to files referenced via #[debugger_visualizer]
4+
# are picked up when compiling incrementally.
5+
6+
# We have to copy the source to $(TMPDIR) because Github CI mounts the source
7+
# directory as readonly. We need to apply modifications to some of the source
8+
# file.
9+
SRC_DIR := $(TMPDIR)/src
10+
INCR_CACHE_DIR := $(TMPDIR)/incremental
11+
12+
all:
13+
rm -rf $(TMPDIR)/*
14+
mkdir $(SRC_DIR)
15+
cp ./foo.rs $(SRC_DIR)
16+
echo "GDB script v1" > $(SRC_DIR)/foo.py
17+
echo "Natvis v1" > $(SRC_DIR)/foo.natvis
18+
$(RUSTC) $(SRC_DIR)/foo.rs \
19+
--crate-type=rlib \
20+
--emit metadata \
21+
-C incremental=$(INCR_CACHE_DIR) \
22+
-Z incremental-verify-ich
23+
$(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta
24+
$(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta
25+
26+
# Change only the GDB script and check that the change has been picked up
27+
echo "GDB script v2" > $(SRC_DIR)/foo.py
28+
$(RUSTC) $(SRC_DIR)/foo.rs \
29+
--crate-type=rlib \
30+
--emit metadata \
31+
-C incremental=$(INCR_CACHE_DIR) \
32+
-Z incremental-verify-ich
33+
34+
$(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta
35+
$(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta
36+
$(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta
37+
38+
# Now change the Natvis version and check that the change has been picked up
39+
echo "Natvis v2" > $(SRC_DIR)/foo.natvis
40+
$(RUSTC) $(SRC_DIR)/foo.rs \
41+
--crate-type=rlib \
42+
--emit metadata \
43+
-C incremental=$(INCR_CACHE_DIR) \
44+
-Z incremental-verify-ich
45+
46+
$(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta
47+
$(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta
48+
$(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta
49+
$(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![debugger_visualizer(natvis_file = "./foo.natvis")]
2+
#![debugger_visualizer(gdb_script_file = "./foo.py")]
3+
4+
pub struct Foo {
5+
pub x: u32,
6+
}

‎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)
Please sign in to comment.