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 https://github.com/rust-lang/rust/issues/111226 Fixes https://github.com/rust-lang/rust/issues/111227 Fixes https://github.com/rust-lang/rust/issues/111295 r? `@wesleywiser` cc `@gibbyfree`
This commit is contained in:
commit
17a681000b
@ -58,7 +58,7 @@ use rustc_errors::{
|
|||||||
use rustc_fluent_macro::fluent_messages;
|
use rustc_fluent_macro::fluent_messages;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||||
use rustc_hir::definitions::DefPathData;
|
use rustc_hir::definitions::DefPathData;
|
||||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
||||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||||
@ -435,6 +435,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
|||||||
// Queries that borrow `resolver_for_lowering`.
|
// Queries that borrow `resolver_for_lowering`.
|
||||||
tcx.ensure_with_value().output_filenames(());
|
tcx.ensure_with_value().output_filenames(());
|
||||||
tcx.ensure_with_value().early_lint_checks(());
|
tcx.ensure_with_value().early_lint_checks(());
|
||||||
|
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
|
||||||
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
|
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
|
||||||
|
|
||||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||||
|
@ -9,10 +9,9 @@ use rustc_ast::attr;
|
|||||||
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
|
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType};
|
||||||
use rustc_session::config::{CrateType, DebugInfo};
|
use rustc_session::config::{CrateType, DebugInfo};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::DebuggerVisualizerType;
|
|
||||||
|
|
||||||
/// Inserts a side-effect free instruction sequence that makes sure that the
|
/// Inserts a side-effect free instruction sequence that makes sure that the
|
||||||
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
|
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
|
||||||
|
@ -9,6 +9,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
|||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_metadata::find_native_static_library;
|
use rustc_metadata::find_native_static_library;
|
||||||
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
|
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
|
||||||
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::dependency_format::Linkage;
|
use rustc_middle::middle::dependency_format::Linkage;
|
||||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
|
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
|
||||||
@ -21,7 +22,6 @@ use rustc_session::utils::NativeLibKind;
|
|||||||
/// need out of the shared crate context before we get rid of it.
|
/// need out of the shared crate context before we get rid of it.
|
||||||
use rustc_session::{filesearch, Session};
|
use rustc_session::{filesearch, Session};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::DebuggerVisualizerFile;
|
|
||||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
|
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
|
||||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
||||||
|
@ -23,6 +23,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
|||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_metadata::EncodedMetadata;
|
use rustc_metadata::EncodedMetadata;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
|
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||||
use rustc_middle::middle::exported_symbols;
|
use rustc_middle::middle::exported_symbols;
|
||||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||||
use rustc_middle::middle::lang_items;
|
use rustc_middle::middle::lang_items;
|
||||||
@ -35,7 +36,6 @@ use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
|
||||||
use rustc_target::abi::{Align, FIRST_VARIANT};
|
use rustc_target::abi::{Align, FIRST_VARIANT};
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
@ -28,6 +28,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
|||||||
use rustc_fluent_macro::fluent_messages;
|
use rustc_fluent_macro::fluent_messages;
|
||||||
use rustc_hir::def_id::CrateNum;
|
use rustc_hir::def_id::CrateNum;
|
||||||
use rustc_middle::dep_graph::WorkProduct;
|
use rustc_middle::dep_graph::WorkProduct;
|
||||||
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::dependency_format::Dependencies;
|
use rustc_middle::middle::dependency_format::Dependencies;
|
||||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||||
use rustc_middle::query::{ExternProviders, Providers};
|
use rustc_middle::query::{ExternProviders, Providers};
|
||||||
@ -38,7 +39,6 @@ use rustc_session::cstore::{self, CrateSource};
|
|||||||
use rustc_session::utils::NativeLibKind;
|
use rustc_session::utils::NativeLibKind;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::DebuggerVisualizerFile;
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
@ -487,6 +487,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||||||
files.push(normalize_path(profile_sample.as_path().to_path_buf()));
|
files.push(normalize_path(profile_sample.as_path().to_path_buf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debugger visualizer files
|
||||||
|
for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
|
||||||
|
files.push(normalize_path(debugger_visualizer.path.clone().unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
if sess.binary_dep_depinfo() {
|
if sess.binary_dep_depinfo() {
|
||||||
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
|
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
|
||||||
if backend.contains('.') {
|
if backend.contains('.') {
|
||||||
|
@ -19,6 +19,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
|
|||||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
use rustc_middle::metadata::ModChild;
|
use rustc_middle::metadata::ModChild;
|
||||||
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
||||||
use rustc_middle::ty::codec::TyDecoder;
|
use rustc_middle::ty::codec::TyDecoder;
|
||||||
@ -958,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||||||
.decode((self, sess))
|
.decode((self, sess))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_debugger_visualizers(self) -> Vec<rustc_span::DebuggerVisualizerFile> {
|
fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> {
|
||||||
self.root.debugger_visualizers.decode(self).collect::<Vec<_>>()
|
self.root.debugger_visualizers.decode(self).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ use rustc_hir::definitions::DefPathData;
|
|||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::dependency_format::Linkage;
|
use rustc_middle::middle::dependency_format::Linkage;
|
||||||
use rustc_middle::middle::exported_symbols::{
|
use rustc_middle::middle::exported_symbols::{
|
||||||
metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
|
metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
|
||||||
@ -36,9 +37,7 @@ use rustc_session::config::{CrateType, OptLevel};
|
|||||||
use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
|
use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
|
||||||
use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
|
use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::{
|
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
|
||||||
self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
|
|
||||||
};
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@ -1855,7 +1854,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
|
|
||||||
fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
|
fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
|
||||||
empty_proc_macro!(self);
|
empty_proc_macro!(self);
|
||||||
self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
|
self.lazy_array(
|
||||||
|
self.tcx
|
||||||
|
.debugger_visualizers(LOCAL_CRATE)
|
||||||
|
.iter()
|
||||||
|
// Erase the path since it may contain privacy sensitive data
|
||||||
|
// that we don't want to end up in crate metadata.
|
||||||
|
// The path is only needed for the local crate because of
|
||||||
|
// `--emit dep-info`.
|
||||||
|
.map(DebuggerVisualizerFile::path_erased),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
|
fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
|
||||||
|
@ -2,6 +2,7 @@ use crate::creader::CrateMetadataRef;
|
|||||||
use decoder::Metadata;
|
use decoder::Metadata;
|
||||||
use def_path_hash_map::DefPathHashMapRef;
|
use def_path_hash_map::DefPathHashMapRef;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use table::TableBuilder;
|
use table::TableBuilder;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
@ -245,7 +246,7 @@ pub(crate) struct CrateRoot {
|
|||||||
proc_macro_data: Option<ProcMacroData>,
|
proc_macro_data: Option<ProcMacroData>,
|
||||||
|
|
||||||
tables: LazyTables,
|
tables: LazyTables,
|
||||||
debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>,
|
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
|
||||||
|
|
||||||
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
|
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::hir::{ModuleItems, Owner};
|
use crate::hir::{ModuleItems, Owner};
|
||||||
|
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use crate::query::LocalCrate;
|
use crate::query::LocalCrate;
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::TyCtxt;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
@ -1165,11 +1166,26 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||||||
|
|
||||||
source_file_names.sort_unstable();
|
source_file_names.sort_unstable();
|
||||||
|
|
||||||
|
// We have to take care of debugger visualizers explicitly. The HIR (and
|
||||||
|
// thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but
|
||||||
|
// these attributes only store the file path to the visualizer file, not
|
||||||
|
// their content. Yet that content is exported into crate metadata, so any
|
||||||
|
// changes to it need to be reflected in the crate hash.
|
||||||
|
let debugger_visualizers: Vec<_> = tcx
|
||||||
|
.debugger_visualizers(LOCAL_CRATE)
|
||||||
|
.iter()
|
||||||
|
// We ignore the path to the visualizer file since it's not going to be
|
||||||
|
// encoded in crate metadata and we already hash the full contents of
|
||||||
|
// the file.
|
||||||
|
.map(DebuggerVisualizerFile::path_erased)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
|
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
|
||||||
let mut stable_hasher = StableHasher::new();
|
let mut stable_hasher = StableHasher::new();
|
||||||
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
|
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
|
||||||
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
|
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
|
||||||
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
|
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
|
||||||
|
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
|
||||||
if tcx.sess.opts.incremental_relative_spans() {
|
if tcx.sess.opts.incremental_relative_spans() {
|
||||||
let definitions = tcx.definitions_untracked();
|
let definitions = tcx.definitions_untracked();
|
||||||
let mut owner_spans: Vec<_> = krate
|
let mut owner_spans: Vec<_> = krate
|
||||||
|
38
compiler/rustc_middle/src/middle/debugger_visualizer.rs
Normal file
38
compiler/rustc_middle/src/middle/debugger_visualizer.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(HashStable)]
|
||||||
|
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
|
||||||
|
pub enum DebuggerVisualizerType {
|
||||||
|
Natvis,
|
||||||
|
GdbPrettyPrinter,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single debugger visualizer file.
|
||||||
|
#[derive(HashStable)]
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
|
||||||
|
pub struct DebuggerVisualizerFile {
|
||||||
|
/// The complete debugger visualizer source.
|
||||||
|
pub src: Lrc<[u8]>,
|
||||||
|
/// Indicates which visualizer type this targets.
|
||||||
|
pub visualizer_type: DebuggerVisualizerType,
|
||||||
|
/// The file path to the visualizer file. This is used for reporting
|
||||||
|
/// visualizer files in dep-info. Before it is written to crate metadata,
|
||||||
|
/// the path is erased to `None`, so as not to emit potentially privacy
|
||||||
|
/// sensitive data.
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebuggerVisualizerFile {
|
||||||
|
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self {
|
||||||
|
DebuggerVisualizerFile { src, visualizer_type, path: Some(path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_erased(&self) -> Self {
|
||||||
|
DebuggerVisualizerFile {
|
||||||
|
src: self.src.clone(),
|
||||||
|
visualizer_type: self.visualizer_type,
|
||||||
|
path: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod codegen_fn_attrs;
|
pub mod codegen_fn_attrs;
|
||||||
|
pub mod debugger_visualizer;
|
||||||
pub mod dependency_format;
|
pub mod dependency_format;
|
||||||
pub mod exported_symbols;
|
pub mod exported_symbols;
|
||||||
pub mod lang_items;
|
pub mod lang_items;
|
||||||
|
@ -12,6 +12,7 @@ use crate::infer::canonical::{self, Canonical};
|
|||||||
use crate::lint::LintExpectation;
|
use crate::lint::LintExpectation;
|
||||||
use crate::metadata::ModChild;
|
use crate::metadata::ModChild;
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
|
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
use crate::middle::lib_features::LibFeatures;
|
use crate::middle::lib_features::LibFeatures;
|
||||||
use crate::middle::privacy::EffectiveVisibilities;
|
use crate::middle::privacy::EffectiveVisibilities;
|
||||||
@ -1784,12 +1785,18 @@ rustc_queries! {
|
|||||||
desc { "looking at the source for a crate" }
|
desc { "looking at the source for a crate" }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the debugger visualizers defined for this crate.
|
/// Returns the debugger visualizers defined for this crate.
|
||||||
query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
|
/// NOTE: This query has to be marked `eval_always` because it reads data
|
||||||
|
/// directly from disk that is not tracked anywhere else. I.e. it
|
||||||
|
/// represents a genuine input to the query system.
|
||||||
|
query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> {
|
||||||
arena_cache
|
arena_cache
|
||||||
desc { "looking up the debugger visualizers for this crate" }
|
desc { "looking up the debugger visualizers for this crate" }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
eval_always
|
||||||
}
|
}
|
||||||
|
|
||||||
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
|
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
|
||||||
eval_always
|
eval_always
|
||||||
desc { "generating a postorder list of CrateNums" }
|
desc { "generating a postorder list of CrateNums" }
|
||||||
|
@ -56,6 +56,7 @@ trivially_parameterized_over_tcx! {
|
|||||||
std::string::String,
|
std::string::String,
|
||||||
crate::metadata::ModChild,
|
crate::metadata::ModChild,
|
||||||
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
|
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
|
||||||
|
crate::middle::debugger_visualizer::DebuggerVisualizerFile,
|
||||||
crate::middle::exported_symbols::SymbolExportInfo,
|
crate::middle::exported_symbols::SymbolExportInfo,
|
||||||
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
|
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
|
||||||
crate::mir::ConstQualifs,
|
crate::mir::ConstQualifs,
|
||||||
@ -91,7 +92,6 @@ trivially_parameterized_over_tcx! {
|
|||||||
rustc_session::cstore::ForeignModule,
|
rustc_session::cstore::ForeignModule,
|
||||||
rustc_session::cstore::LinkagePreference,
|
rustc_session::cstore::LinkagePreference,
|
||||||
rustc_session::cstore::NativeLib,
|
rustc_session::cstore::NativeLib,
|
||||||
rustc_span::DebuggerVisualizerFile,
|
|
||||||
rustc_span::ExpnData,
|
rustc_span::ExpnData,
|
||||||
rustc_span::ExpnHash,
|
rustc_span::ExpnHash,
|
||||||
rustc_span::ExpnId,
|
rustc_span::ExpnId,
|
||||||
|
@ -8,7 +8,6 @@ use crate::{errors, fluent_generated as fluent};
|
|||||||
use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
|
use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
|
use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
|
||||||
use rustc_expand::base::resolve_path;
|
|
||||||
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
@ -1916,6 +1915,10 @@ impl CheckAttrVisitor<'_> {
|
|||||||
|
|
||||||
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
|
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
|
||||||
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
|
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
|
||||||
|
// Here we only check that the #[debugger_visualizer] attribute is attached
|
||||||
|
// to nothing other than a module. All other checks are done in the
|
||||||
|
// `debugger_visualizer` query where they need to be done for decoding
|
||||||
|
// anyway.
|
||||||
match target {
|
match target {
|
||||||
Target::Mod => {}
|
Target::Mod => {}
|
||||||
_ => {
|
_ => {
|
||||||
@ -1924,53 +1927,7 @@ impl CheckAttrVisitor<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(hints) = attr.meta_item_list() else {
|
true
|
||||||
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let hint = match hints.len() {
|
|
||||||
1 => &hints[0],
|
|
||||||
_ => {
|
|
||||||
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(meta_item) = hint.meta_item() else {
|
|
||||||
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
|
||||||
(sym::natvis_file, Some(value)) => value,
|
|
||||||
(sym::gdb_script_file, Some(value)) => value,
|
|
||||||
(_, _) => {
|
|
||||||
self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let file =
|
|
||||||
match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(mut err) => {
|
|
||||||
err.emit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match std::fs::File::open(&file) {
|
|
||||||
Ok(_) => true,
|
|
||||||
Err(error) => {
|
|
||||||
self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable {
|
|
||||||
span: meta_item.span,
|
|
||||||
file: &file,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
||||||
|
@ -1,60 +1,69 @@
|
|||||||
//! Detecting usage of the `#[debugger_visualizer]` attribute.
|
//! Detecting usage of the `#[debugger_visualizer]` attribute.
|
||||||
|
|
||||||
use hir::CRATE_HIR_ID;
|
use rustc_ast::Attribute;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_expand::base::resolve_path;
|
use rustc_expand::base::resolve_path;
|
||||||
use rustc_hir as hir;
|
use rustc_middle::{
|
||||||
use rustc_hir::HirId;
|
middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType},
|
||||||
use rustc_middle::query::{LocalCrate, Providers};
|
query::{LocalCrate, Providers},
|
||||||
use rustc_middle::ty::TyCtxt;
|
ty::TyCtxt,
|
||||||
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
};
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
use crate::errors::DebugVisualizerUnreadable;
|
use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
|
||||||
|
|
||||||
fn check_for_debugger_visualizer(
|
impl DebuggerVisualizerCollector<'_> {
|
||||||
tcx: TyCtxt<'_>,
|
fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
|
||||||
hir_id: HirId,
|
|
||||||
debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
|
|
||||||
) {
|
|
||||||
let attrs = tcx.hir().attrs(hir_id);
|
|
||||||
for attr in attrs {
|
|
||||||
if attr.has_name(sym::debugger_visualizer) {
|
if attr.has_name(sym::debugger_visualizer) {
|
||||||
let Some(list) = attr.meta_item_list() else {
|
let Some(hints) = attr.meta_item_list() else {
|
||||||
continue
|
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta_item = match list.len() {
|
let hint = if hints.len() == 1 {
|
||||||
1 => match list[0].meta_item() {
|
&hints[0]
|
||||||
Some(meta_item) => meta_item,
|
} else {
|
||||||
_ => continue,
|
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||||
},
|
return;
|
||||||
_ => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let visualizer_type = match meta_item.name_or_empty() {
|
let Some(meta_item) = hint.meta_item() else {
|
||||||
sym::natvis_file => DebuggerVisualizerType::Natvis,
|
self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||||
sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
|
return;
|
||||||
_ => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let file = match meta_item.value_str() {
|
let (visualizer_type, visualizer_path) =
|
||||||
Some(value) => {
|
match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||||
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
|
(sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value),
|
||||||
Ok(file) => file,
|
(sym::gdb_script_file, Some(value)) => {
|
||||||
_ => continue,
|
(DebuggerVisualizerType::GdbPrettyPrinter, value)
|
||||||
}
|
}
|
||||||
}
|
(_, _) => {
|
||||||
None => continue,
|
self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span });
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file =
|
||||||
|
match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(mut err) => {
|
||||||
|
err.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match std::fs::read(&file) {
|
match std::fs::read(&file) {
|
||||||
Ok(contents) => {
|
Ok(contents) => {
|
||||||
debugger_visualizers
|
self.visualizers.push(DebuggerVisualizerFile::new(
|
||||||
.insert(DebuggerVisualizerFile::new(Lrc::from(contents), visualizer_type));
|
Lrc::from(contents),
|
||||||
|
visualizer_type,
|
||||||
|
file,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tcx.sess.emit_err(DebugVisualizerUnreadable {
|
self.sess.emit_err(DebugVisualizerUnreadable {
|
||||||
span: meta_item.span,
|
span: meta_item.span,
|
||||||
file: &file,
|
file: &file,
|
||||||
error,
|
error,
|
||||||
@ -65,29 +74,30 @@ fn check_for_debugger_visualizer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DebuggerVisualizerCollector<'a> {
|
||||||
|
sess: &'a Session,
|
||||||
|
visualizers: Vec<DebuggerVisualizerFile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
|
||||||
|
fn visit_attribute(&mut self, attr: &'ast Attribute) {
|
||||||
|
self.check_for_debugger_visualizer(attr);
|
||||||
|
rustc_ast::visit::walk_attribute(self, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Traverses and collects the debugger visualizers for a specific crate.
|
/// Traverses and collects the debugger visualizers for a specific crate.
|
||||||
fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
|
fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
|
||||||
// Initialize the collector.
|
let resolver_and_krate = tcx.resolver_for_lowering(()).borrow();
|
||||||
let mut debugger_visualizers = FxHashSet::default();
|
let krate = &*resolver_and_krate.1;
|
||||||
|
|
||||||
// Collect debugger visualizers in this crate.
|
let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() };
|
||||||
tcx.hir().for_each_module(|id| {
|
rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate);
|
||||||
check_for_debugger_visualizer(
|
|
||||||
tcx,
|
|
||||||
tcx.hir().local_def_id_to_hir_id(id),
|
|
||||||
&mut debugger_visualizers,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collect debugger visualizers on the crate attributes.
|
// We are collecting visualizers in AST-order, which is deterministic,
|
||||||
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
|
// so we don't need to do any explicit sorting in order to get a
|
||||||
|
// deterministic query result
|
||||||
// Extract out the found debugger_visualizer items.
|
visitor.visualizers
|
||||||
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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
@ -1257,29 +1257,6 @@ impl SourceFileHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(HashStable_Generic)]
|
|
||||||
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
|
|
||||||
pub enum DebuggerVisualizerType {
|
|
||||||
Natvis,
|
|
||||||
GdbPrettyPrinter,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A single debugger visualizer file.
|
|
||||||
#[derive(HashStable_Generic)]
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
|
|
||||||
pub struct DebuggerVisualizerFile {
|
|
||||||
/// The complete debugger visualizer source.
|
|
||||||
pub src: Lrc<[u8]>,
|
|
||||||
/// Indicates which visualizer type this targets.
|
|
||||||
pub visualizer_type: DebuggerVisualizerType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DebuggerVisualizerFile {
|
|
||||||
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
|
|
||||||
DebuggerVisualizerFile { src, visualizer_type }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum SourceFileLines {
|
pub enum SourceFileLines {
|
||||||
/// The source file lines, in decoded (random-access) form.
|
/// The source file lines, in decoded (random-access) form.
|
||||||
|
@ -35,6 +35,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
|
|||||||
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
|
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
|
||||||
"tests/ui/unused-crate-deps/test.mk", // why would you use make
|
"tests/ui/unused-crate-deps/test.mk", // why would you use make
|
||||||
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
|
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
|
||||||
|
"tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
|
||||||
];
|
];
|
||||||
|
|
||||||
fn check_entries(tests_path: &Path, bad: &mut bool) {
|
fn check_entries(tests_path: &Path, bad: &mut bool) {
|
||||||
|
9
tests/run-make/debugger-visualizer-dep-info/Makefile
Normal file
9
tests/run-make/debugger-visualizer-dep-info/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
# This test makes sure that files referenced via #[debugger_visualizer] are
|
||||||
|
# included in `--emit dep-info` output.
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) --emit dep-info main.rs
|
||||||
|
$(CGREP) "foo.py" < $(TMPDIR)/main.d
|
||||||
|
$(CGREP) "my_visualizers/bar.natvis" < $(TMPDIR)/main.d
|
1
tests/run-make/debugger-visualizer-dep-info/foo.py
Normal file
1
tests/run-make/debugger-visualizer-dep-info/foo.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# empty
|
12
tests/run-make/debugger-visualizer-dep-info/main.rs
Normal file
12
tests/run-make/debugger-visualizer-dep-info/main.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#![debugger_visualizer(gdb_script_file = "foo.py")]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
const _UNUSED: u32 = {
|
||||||
|
mod inner {
|
||||||
|
#![debugger_visualizer(natvis_file = "my_visualizers/bar.natvis")]
|
||||||
|
pub const XYZ: u32 = 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
inner::XYZ + 1
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<!-- empty -->
|
49
tests/run-make/incremental-debugger-visualizer/Makefile
Normal file
49
tests/run-make/incremental-debugger-visualizer/Makefile
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
# This test makes sure that changes to files referenced via #[debugger_visualizer]
|
||||||
|
# are picked up when compiling incrementally.
|
||||||
|
|
||||||
|
# We have to copy the source to $(TMPDIR) because Github CI mounts the source
|
||||||
|
# directory as readonly. We need to apply modifications to some of the source
|
||||||
|
# file.
|
||||||
|
SRC_DIR := $(TMPDIR)/src
|
||||||
|
INCR_CACHE_DIR := $(TMPDIR)/incremental
|
||||||
|
|
||||||
|
all:
|
||||||
|
rm -rf $(TMPDIR)/*
|
||||||
|
mkdir $(SRC_DIR)
|
||||||
|
cp ./foo.rs $(SRC_DIR)
|
||||||
|
echo "GDB script v1" > $(SRC_DIR)/foo.py
|
||||||
|
echo "Natvis v1" > $(SRC_DIR)/foo.natvis
|
||||||
|
$(RUSTC) $(SRC_DIR)/foo.rs \
|
||||||
|
--crate-type=rlib \
|
||||||
|
--emit metadata \
|
||||||
|
-C incremental=$(INCR_CACHE_DIR) \
|
||||||
|
-Z incremental-verify-ich
|
||||||
|
$(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
|
||||||
|
# Change only the GDB script and check that the change has been picked up
|
||||||
|
echo "GDB script v2" > $(SRC_DIR)/foo.py
|
||||||
|
$(RUSTC) $(SRC_DIR)/foo.rs \
|
||||||
|
--crate-type=rlib \
|
||||||
|
--emit metadata \
|
||||||
|
-C incremental=$(INCR_CACHE_DIR) \
|
||||||
|
-Z incremental-verify-ich
|
||||||
|
|
||||||
|
$(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
|
||||||
|
# Now change the Natvis version and check that the change has been picked up
|
||||||
|
echo "Natvis v2" > $(SRC_DIR)/foo.natvis
|
||||||
|
$(RUSTC) $(SRC_DIR)/foo.rs \
|
||||||
|
--crate-type=rlib \
|
||||||
|
--emit metadata \
|
||||||
|
-C incremental=$(INCR_CACHE_DIR) \
|
||||||
|
-Z incremental-verify-ich
|
||||||
|
|
||||||
|
$(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta
|
||||||
|
$(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta
|
6
tests/run-make/incremental-debugger-visualizer/foo.rs
Normal file
6
tests/run-make/incremental-debugger-visualizer/foo.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#![debugger_visualizer(natvis_file = "./foo.natvis")]
|
||||||
|
#![debugger_visualizer(gdb_script_file = "./foo.py")]
|
||||||
|
|
||||||
|
pub struct Foo {
|
||||||
|
pub x: u32,
|
||||||
|
}
|
1
tests/ui/invalid/foo.natvis.xml
Normal file
1
tests/ui/invalid/foo.natvis.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!-- empty -->
|
@ -1,2 +1,2 @@
|
|||||||
#[debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR attribute should be applied to a module
|
#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: attribute should be applied to a module
|
error: attribute should be applied to a module
|
||||||
--> $DIR/invalid-debugger-visualizer-target.rs:1:1
|
--> $DIR/invalid-debugger-visualizer-target.rs:1:1
|
||||||
|
|
|
|
||||||
LL | #[debugger_visualizer(natvis_file = "../foo.natvis")]
|
LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user