Fix dependency tracking for debugger visualizers
This commit is contained in:
parent
72b2716246
commit
7f01893900
@ -486,6 +486,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('.') {
|
||||||
@ -567,6 +572,12 @@ fn resolver_for_lowering<'tcx>(
|
|||||||
// Make sure we don't mutate the cstore from here on.
|
// Make sure we don't mutate the cstore from here on.
|
||||||
tcx.untracked().cstore.leak();
|
tcx.untracked().cstore.leak();
|
||||||
|
|
||||||
|
{
|
||||||
|
let debugger_visualizers = rustc_passes::debugger_visualizer::collect(tcx.sess, &krate);
|
||||||
|
let feed = tcx.feed_local_crate();
|
||||||
|
feed.debugger_visualizers(debugger_visualizers);
|
||||||
|
}
|
||||||
|
|
||||||
let ty::ResolverOutputs {
|
let ty::ResolverOutputs {
|
||||||
global_ctxt: untracked_resolutions,
|
global_ctxt: untracked_resolutions,
|
||||||
ast_lowering: untracked_resolver_for_lowering,
|
ast_lowering: untracked_resolver_for_lowering,
|
||||||
|
@ -1852,7 +1852,16 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
|
|||||||
|
|
||||||
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> {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_span::def_id::StableCrateId;
|
use rustc_span::def_id::StableCrateId;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::{DebuggerVisualizerFile, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -1165,11 +1165,21 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||||||
|
|
||||||
source_file_names.sort_unstable();
|
source_file_names.sort_unstable();
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -1795,6 +1795,7 @@
|
|||||||
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
|
||||||
|
feedable
|
||||||
}
|
}
|
||||||
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
|
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
|
||||||
eval_always
|
eval_always
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
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,7 @@ fn check_allow_internal_unstable(
|
|||||||
|
|
||||||
/// 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 {
|
||||||
|
// FIXME: mention that other checks are done in the query provider
|
||||||
match target {
|
match target {
|
||||||
Target::Mod => {}
|
Target::Mod => {}
|
||||||
_ => {
|
_ => {
|
||||||
@ -1924,53 +1924,7 @@ fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,64 @@
|
|||||||
//! 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_session::Session;
|
||||||
use rustc_hir::HirId;
|
|
||||||
use rustc_middle::query::{LocalCrate, Providers};
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
|
||||||
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||||
|
|
||||||
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),
|
||||||
|
(sym::gdb_script_file, Some(value)) => {
|
||||||
|
(DebuggerVisualizerType::GdbPrettyPrinter, value)
|
||||||
|
}
|
||||||
|
(_, _) => {
|
||||||
|
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,
|
Ok(file) => file,
|
||||||
_ => continue,
|
Err(mut err) => {
|
||||||
|
err.emit();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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,31 +69,25 @@ 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> {
|
pub fn collect(sess: &Session, krate: &rustc_ast::ast::Crate) -> Vec<DebuggerVisualizerFile> {
|
||||||
// Initialize the collector.
|
// Initialize the collector.
|
||||||
let mut debugger_visualizers = FxHashSet::default();
|
let mut visitor = DebuggerVisualizerCollector { sess, visualizers: Vec::new() };
|
||||||
|
rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate);
|
||||||
// Collect debugger visualizers in this crate.
|
|
||||||
tcx.hir().for_each_module(|id| {
|
|
||||||
check_for_debugger_visualizer(
|
|
||||||
tcx,
|
|
||||||
tcx.hir().local_def_id_to_hir_id(id),
|
|
||||||
&mut debugger_visualizers,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collect debugger visualizers on the crate attributes.
|
|
||||||
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
|
|
||||||
|
|
||||||
// Extract out the found debugger_visualizer items.
|
|
||||||
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Sort the visualizers so we always get a deterministic query result.
|
// Sort the visualizers so we always get a deterministic query result.
|
||||||
visualizers.sort();
|
visitor.visualizers.sort_unstable();
|
||||||
visualizers
|
visitor.visualizers
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
|
||||||
providers.debugger_visualizers = debugger_visualizers;
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
mod check_attr;
|
mod check_attr;
|
||||||
mod check_const;
|
mod check_const;
|
||||||
pub mod dead;
|
pub mod dead;
|
||||||
mod debugger_visualizer;
|
pub mod debugger_visualizer;
|
||||||
mod diagnostic_items;
|
mod diagnostic_items;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
mod errors;
|
mod errors;
|
||||||
@ -50,7 +50,6 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
check_attr::provide(providers);
|
check_attr::provide(providers);
|
||||||
check_const::provide(providers);
|
check_const::provide(providers);
|
||||||
dead::provide(providers);
|
dead::provide(providers);
|
||||||
debugger_visualizer::provide(providers);
|
|
||||||
diagnostic_items::provide(providers);
|
diagnostic_items::provide(providers);
|
||||||
entry::provide(providers);
|
entry::provide(providers);
|
||||||
lang_items::provide(providers);
|
lang_items::provide(providers);
|
||||||
|
@ -1272,11 +1272,21 @@ pub struct DebuggerVisualizerFile {
|
|||||||
pub src: Lrc<[u8]>,
|
pub src: Lrc<[u8]>,
|
||||||
/// Indicates which visualizer type this targets.
|
/// Indicates which visualizer type this targets.
|
||||||
pub visualizer_type: DebuggerVisualizerType,
|
pub visualizer_type: DebuggerVisualizerType,
|
||||||
|
// FIXME: Docs
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebuggerVisualizerFile {
|
impl DebuggerVisualizerFile {
|
||||||
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
|
pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self {
|
||||||
DebuggerVisualizerFile { src, visualizer_type }
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"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) {
|
||||||
|
8
tests/run-make/debugger-visualizer-dep-info/Makefile
Normal file
8
tests/run-make/debugger-visualizer-dep-info/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# ignore-windows-gnu
|
||||||
|
|
||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) --emit dep-info main.rs
|
||||||
|
$(CGREP) "foo.py" < $(TMPDIR)/main.d
|
||||||
|
$(CGREP) "my_visualizers/bar.py" < $(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(gdb_script_file = "my_visualizers/bar.py")]
|
||||||
|
pub const XYZ: u32 = 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
inner::XYZ + 1
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
# empty
|
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…
Reference in New Issue
Block a user