Rollup merge of #146704 - jdonszelmann:port-debug-visualizer, r=petrochenkov

port `#[debugger_visualizer]` to the new attribute system
This commit is contained in:
Matthias Krüger 2025-09-26 18:11:09 +02:00 committed by GitHub
commit d09bb02eb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 185 additions and 154 deletions

View file

@ -0,0 +1,60 @@
use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};
use super::prelude::*;
pub(crate) struct DebuggerViualizerParser;
impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
const PATH: &[Symbol] = &[sym::debugger_visualizer];
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(
List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
);
type Item = DebugVisualizer;
const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
let Some(l) = args.list() else {
cx.expected_list(args.span().unwrap_or(cx.attr_span));
return None;
};
let Some(single) = l.single() else {
cx.expected_single_argument(l.span);
return None;
};
let Some(mi) = single.meta_item() else {
cx.expected_name_value(single.span(), None);
return None;
};
let path = mi.path().word_sym();
let visualizer_type = match path {
Some(sym::natvis_file) => DebuggerVisualizerType::Natvis,
Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter,
_ => {
cx.expected_specific_argument(
mi.path().span(),
&[sym::natvis_file, sym::gdb_script_file],
);
return None;
}
};
let Some(path) = mi.args().name_value() else {
cx.expected_name_value(single.span(), path);
return None;
};
let Some(path) = path.value_as_str() else {
cx.expected_string_literal(path.value_span, Some(path.value_as_lit()));
return None;
};
Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
}
}

View file

@ -36,6 +36,7 @@ pub(crate) mod cfg_old;
pub(crate) mod codegen_attrs;
pub(crate) mod confusables;
pub(crate) mod crate_level;
pub(crate) mod debugger;
pub(crate) mod deprecation;
pub(crate) mod dummy;
pub(crate) mod inline;

View file

@ -28,6 +28,7 @@ use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@ -163,6 +164,7 @@ attribute_parsers!(
// tidy-alphabetical-start
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<DebuggerViualizerParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,

View file

@ -2,9 +2,9 @@
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
use rustc_hir::attrs::DebuggerVisualizerType;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
use rustc_session::config::{CrateType, DebugInfo};
use crate::builder::Builder;

View file

@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
use rustc_data_structures::unord::UnordMap;
use rustc_hir::attrs::OptimizeAttr;
use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemId, Target};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
use rustc_middle::middle::lang_items;

View file

@ -363,6 +363,20 @@ pub struct LinkEntry {
pub import_name_type: Option<(PeImportNameType, Span)>,
}
#[derive(HashStable_Generic, PrintAttribute)]
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
pub enum DebuggerVisualizerType {
Natvis,
GdbPrettyPrinter,
}
#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
pub struct DebugVisualizer {
pub span: Span,
pub visualizer_type: DebuggerVisualizerType,
pub path: Symbol,
}
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@ -485,7 +499,10 @@ pub enum AttributeKind {
/// Represents `#[custom_mir]`.
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
///Represents `#[rustc_deny_explicit_impl]`.
/// Represents `#[debugger_visualizer]`.
DebuggerVisualizer(ThinVec<DebugVisualizer>),
/// Represents `#[rustc_deny_explicit_impl]`.
DenyExplicitImpl(Span),
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).

View file

@ -37,6 +37,7 @@ impl AttributeKind {
Coverage(..) => No,
CrateName { .. } => No,
CustomMir(_, _, _) => Yes,
DebuggerVisualizer(..) => No,
DenyExplicitImpl(..) => No,
Deprecation { .. } => Yes,
DoNotImplementViaObject(..) => No,

View file

@ -1,15 +1,9 @@
use std::path::PathBuf;
use std::sync::Arc;
use rustc_hir::attrs::DebuggerVisualizerType;
use rustc_macros::{Decodable, Encodable, HashStable};
#[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)]

View file

@ -93,15 +93,6 @@ passes_dead_codes =
}
} never {$participle}
passes_debug_visualizer_invalid =
invalid argument
.note_1 = expected: `natvis_file = "..."`
.note_2 = OR
.note_3 = expected: `gdb_script_file = "..."`
passes_debug_visualizer_placement =
attribute should be applied to a module
passes_debug_visualizer_unreadable =
couldn't read {$file}: {$error}

View file

@ -282,6 +282,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::ObjcClass { .. }
| AttributeKind::ObjcSelector { .. }
| AttributeKind::RustcCoherenceIsCore(..)
| AttributeKind::DebuggerVisualizer(..)
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
@ -302,7 +303,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
&mut doc_aliases,
),
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
[sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
[sym::rustc_no_implicit_autorefs, ..] => {
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
}
@ -1783,20 +1783,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
// 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 {
Target::Mod => {}
_ => {
self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
}
}
}
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
/// (Allows proc_macro functions)
fn check_rustc_allow_const_fn_unstable(

View file

@ -1,67 +1,60 @@
//! Detecting usage of the `#[debugger_visualizer]` attribute.
use rustc_ast::Attribute;
use rustc_ast::ast::NodeId;
use rustc_ast::{HasNodeId, ItemKind, ast};
use rustc_attr_parsing::AttributeParser;
use rustc_expand::base::resolve_path;
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_hir::Attribute;
use rustc_hir::attrs::{AttributeKind, DebugVisualizer};
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::sym;
use rustc_span::{DUMMY_SP, Span, sym};
use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
use crate::errors::DebugVisualizerUnreadable;
impl DebuggerVisualizerCollector<'_> {
fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
if attr.has_name(sym::debugger_visualizer) {
let Some(hints) = attr.meta_item_list() else {
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
return;
};
fn check_for_debugger_visualizer(
&mut self,
attrs: &[ast::Attribute],
span: Span,
node_id: NodeId,
) {
if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
AttributeParser::parse_limited(
&self.sess,
attrs,
sym::debugger_visualizer,
span,
node_id,
None,
)
{
for DebugVisualizer { span, visualizer_type, path } in visualizers {
let file = match resolve_path(&self.sess, path.as_str(), span) {
Ok(file) => file,
Err(err) => {
err.emit();
return;
}
};
let [hint] = hints.as_slice() else {
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
return;
};
let Some(meta_item) = hint.meta_item() else {
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
return;
};
let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
{
(Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
(Some(sym::gdb_script_file), Some(value)) => {
(DebuggerVisualizerType::GdbPrettyPrinter, value)
}
(_, _) => {
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
return;
}
};
let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file,
Err(err) => {
err.emit();
return;
}
};
match self.sess.source_map().load_binary_file(&file) {
Ok((source, _)) => {
self.visualizers.push(DebuggerVisualizerFile::new(
source,
visualizer_type,
file,
));
}
Err(error) => {
self.sess.dcx().emit_err(DebugVisualizerUnreadable {
span: meta_item.span,
file: &file,
error,
});
match self.sess.source_map().load_binary_file(&file) {
Ok((source, _)) => {
self.visualizers.push(DebuggerVisualizerFile::new(
source,
visualizer_type,
file,
));
}
Err(error) => {
self.sess.dcx().emit_err(DebugVisualizerUnreadable {
span,
file: &file,
error,
});
}
}
}
}
@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> {
}
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);
fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
if let ItemKind::Mod(..) = item.kind {
self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
}
rustc_ast::visit::walk_item(self, item);
}
fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
rustc_ast::visit::walk_crate(self, krate);
}
}

View file

@ -475,23 +475,6 @@ pub(crate) struct MacroOnlyAttribute {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_debug_visualizer_placement)]
pub(crate) struct DebugVisualizerPlacement {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_debug_visualizer_invalid)]
#[note(passes_note_1)]
#[note(passes_note_2)]
#[note(passes_note_3)]
pub(crate) struct DebugVisualizerInvalid {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_debug_visualizer_unreadable)]
pub(crate) struct DebugVisualizerUnreadable<'a> {

View file

@ -185,8 +185,7 @@ extern "C" {
#[forbid]
//~^ ERROR malformed
#[debugger_visualizer]
//~^ ERROR invalid argument
//~| ERROR malformed `debugger_visualizer` attribute input
//~^ ERROR malformed `debugger_visualizer` attribute input
#[automatically_derived = 18]
//~^ ERROR malformed
mod yooo {

View file

@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
| ++++++++++++++++++++++++++++++++++++++++++++
error[E0463]: can't find crate for `wloop`
--> $DIR/malformed-attrs.rs:210:1
--> $DIR/malformed-attrs.rs:209:1
|
LL | extern crate wloop;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
@ -156,22 +156,14 @@ LL | #[forbid(lint1, lint2, ...)]
LL | #[forbid(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `debugger_visualizer` attribute input
--> $DIR/malformed-attrs.rs:187:1
|
LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
|
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:202:1
--> $DIR/malformed-attrs.rs:201:1
|
LL | #[thread_local()]
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
error: malformed `no_link` attribute input
--> $DIR/malformed-attrs.rs:206:1
--> $DIR/malformed-attrs.rs:205:1
|
LL | #[no_link()]
| ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
@ -197,7 +189,7 @@ LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^
error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
--> $DIR/malformed-attrs.rs:215:1
--> $DIR/malformed-attrs.rs:214:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -226,16 +218,6 @@ LL | #[doc]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
= note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
error: invalid argument
--> $DIR/malformed-attrs.rs:187:1
|
LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected: `natvis_file = "..."`
= note: OR
= note: expected: `gdb_script_file = "..."`
error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:29:1
|
@ -685,8 +667,19 @@ LL | #[linkage = "external"]
| ++++++++++++
= and 5 other candidates
error[E0539]: malformed `debugger_visualizer` attribute input
--> $DIR/malformed-attrs.rs:187:1
|
LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^
| |
| expected this to be a list
| help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
|
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error[E0565]: malformed `automatically_derived` attribute input
--> $DIR/malformed-attrs.rs:190:1
--> $DIR/malformed-attrs.rs:189:1
|
LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^----^
@ -695,7 +688,7 @@ LL | #[automatically_derived = 18]
| help: must be of the form: `#[automatically_derived]`
error[E0565]: malformed `non_exhaustive` attribute input
--> $DIR/malformed-attrs.rs:196:1
--> $DIR/malformed-attrs.rs:195:1
|
LL | #[non_exhaustive = 1]
| ^^^^^^^^^^^^^^^^^---^
@ -704,19 +697,19 @@ LL | #[non_exhaustive = 1]
| help: must be of the form: `#[non_exhaustive]`
error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]`
--> $DIR/malformed-attrs.rs:208:1
--> $DIR/malformed-attrs.rs:207:1
|
LL | #[macro_use = 1]
| ^^^^^^^^^^^^^^^^
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
--> $DIR/malformed-attrs.rs:213:1
--> $DIR/malformed-attrs.rs:212:1
|
LL | #[macro_export = 18]
| ^^^^^^^^^^^^^^^^^^^^
error[E0565]: malformed `allow_internal_unsafe` attribute input
--> $DIR/malformed-attrs.rs:215:1
--> $DIR/malformed-attrs.rs:214:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^
@ -800,7 +793,7 @@ LL | #[ignore()]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:222:1
--> $DIR/malformed-attrs.rs:221:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^
@ -819,7 +812,7 @@ LL | #[coroutine = 63] || {}
= note: expected unit type `()`
found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}`
error: aborting due to 77 previous errors; 3 warnings emitted
error: aborting due to 76 previous errors; 3 warnings emitted
Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
For more information about an error, try `rustc --explain E0308`.
@ -871,7 +864,7 @@ LL | #[ignore()]
Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:222:1
--> $DIR/malformed-attrs.rs:221:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^

View file

@ -1,6 +1,6 @@
//@ normalize-stderr: "foo.random:.*\(" -> "foo.random: $$FILE_NOT_FOUND_MSG ("
//@ normalize-stderr: "os error \d+" -> "os error $$FILE_NOT_FOUND_CODE"
#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR invalid argument
#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR malformed `debugger_visualizer` attribute input
#![debugger_visualizer(natvis_file = "../foo.random")] //~ ERROR
fn main() {}

View file

@ -1,18 +1,20 @@
error: invalid argument
--> $DIR/invalid-debugger-visualizer-option.rs:4:24
|
LL | #![debugger_visualizer(random_file = "../foo.random")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected: `natvis_file = "..."`
= note: OR
= note: expected: `gdb_script_file = "..."`
error: couldn't read $DIR/../foo.random: $FILE_NOT_FOUND_MSG (os error $FILE_NOT_FOUND_CODE)
--> $DIR/invalid-debugger-visualizer-option.rs:5:24
|
LL | #![debugger_visualizer(natvis_file = "../foo.random")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0539]: malformed `debugger_visualizer` attribute input
--> $DIR/invalid-debugger-visualizer-option.rs:4:1
|
LL | #![debugger_visualizer(random_file = "../foo.random")]
| ^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^
| | |
| | valid arguments are `natvis_file` or `gdb_script_file`
| help: must be of the form: `#![debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
|
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0539`.

View file

@ -1,2 +1,3 @@
#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module
#[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
//~^ ERROR `#[debugger_visualizer]` attribute cannot be used on functions
fn main() {}

View file

@ -1,8 +1,10 @@
error: attribute should be applied to a module
error: `#[debugger_visualizer]` attribute cannot be used on functions
--> $DIR/invalid-debugger-visualizer-target.rs:1:1
|
LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[debugger_visualizer]` can be applied to modules and crates
error: aborting due to 1 previous error