mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #152988 - JonathanBrouwer:register-tool, r=jdonszelmann
Port `#[register_tool]` to the new attribute system For https://github.com/rust-lang/rust/issues/131229#issuecomment-2971351163 Rebase of https://github.com/rust-lang/rust/pull/146702 r? @jdonszelmann
This commit is contained in:
@@ -347,3 +347,50 @@ fn extend(
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RegisterToolParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for RegisterToolParser {
|
||||
const PATH: &[Symbol] = &[sym::register_tool];
|
||||
type Item = Ident;
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::RegisterTool;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["tool1, tool2, ..."]);
|
||||
|
||||
fn extend(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.warn_empty_attribute(cx.attr_span);
|
||||
}
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
for elem in list.mixed() {
|
||||
let Some(elem) = elem.meta_item() else {
|
||||
cx.expected_identifier(elem.span());
|
||||
continue;
|
||||
};
|
||||
if let Err(arg_span) = elem.args().no_args() {
|
||||
cx.expected_no_args(arg_span);
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = elem.path();
|
||||
let Some(ident) = path.word() else {
|
||||
cx.expected_identifier(path.span());
|
||||
continue;
|
||||
};
|
||||
|
||||
res.push(ident);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ mod late {
|
||||
Combine<FeatureParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
Combine<RegisterToolParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<RustcCleanParser>,
|
||||
Combine<RustcLayoutParser>,
|
||||
|
||||
@@ -707,8 +707,9 @@ fn print_crate_info(
|
||||
};
|
||||
let crate_name = passes::get_crate_name(sess, attrs);
|
||||
let lint_store = crate::unerased_lint_store(sess);
|
||||
let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs);
|
||||
let features = rustc_expand::config::features(sess, attrs, crate_name);
|
||||
let registered_tools =
|
||||
rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess, &features);
|
||||
let lint_levels = rustc_lint::LintLevelsBuilder::crate_root(
|
||||
sess,
|
||||
&features,
|
||||
|
||||
@@ -1154,6 +1154,9 @@ pub enum AttributeKind {
|
||||
/// Represents `#[reexport_test_harness_main]`
|
||||
ReexportTestHarnessMain(Symbol),
|
||||
|
||||
/// Represents `#[register_tool]`
|
||||
RegisterTool(ThinVec<Ident>, Span),
|
||||
|
||||
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
|
||||
Repr {
|
||||
reprs: ThinVec<(ReprAttr, Span)>,
|
||||
|
||||
@@ -94,6 +94,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
|
||||
ProfilerRuntime => No,
|
||||
RecursionLimit { .. } => No,
|
||||
ReexportTestHarnessMain(..) => No,
|
||||
RegisterTool(..) => No,
|
||||
Repr { .. } => No,
|
||||
RustcAbi { .. } => No,
|
||||
RustcAllocator => No,
|
||||
|
||||
@@ -292,6 +292,7 @@ fn check_attributes(
|
||||
| AttributeKind::ProfilerRuntime
|
||||
| AttributeKind::RecursionLimit { .. }
|
||||
| AttributeKind::ReexportTestHarnessMain(..)
|
||||
| AttributeKind::RegisterTool(..)
|
||||
// handled below this loop and elsewhere
|
||||
| AttributeKind::Repr { .. }
|
||||
| AttributeKind::RustcAbi { .. }
|
||||
@@ -404,8 +405,7 @@ fn check_attributes(
|
||||
| sym::rustc_layout
|
||||
| sym::rustc_autodiff
|
||||
// crate-level attrs, are checked below
|
||||
| sym::feature
|
||||
| sym::register_tool,
|
||||
| sym::feature,
|
||||
..
|
||||
] => {}
|
||||
[name, rest@..] => {
|
||||
|
||||
@@ -1201,15 +1201,6 @@ pub(crate) struct ToolWasAlreadyRegistered {
|
||||
pub(crate) old_ident_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$tool}` only accepts identifiers")]
|
||||
pub(crate) struct ToolOnlyAcceptsIdentifiers {
|
||||
#[primary_span]
|
||||
#[label("not an identifier")]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) tool: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum DefinedHere {
|
||||
#[label("similarly named {$candidate_descr} `{$candidate}` defined here")]
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast, Crate, NodeId, attr};
|
||||
use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
|
||||
@@ -15,12 +16,14 @@
|
||||
use rustc_expand::expand::{
|
||||
AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
|
||||
};
|
||||
use rustc_hir::StabilityLevel;
|
||||
use rustc_hir::attrs::{CfgEntry, StrippedCfgItem};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem};
|
||||
use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
|
||||
use rustc_hir::{Attribute, StabilityLevel};
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{
|
||||
LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||
UNUSED_MACRO_RULES, UNUSED_MACROS,
|
||||
@@ -122,35 +125,38 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
|
||||
|
||||
pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
|
||||
let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow();
|
||||
registered_tools_ast(tcx.dcx(), pre_configured_attrs)
|
||||
registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess, tcx.features())
|
||||
}
|
||||
|
||||
pub fn registered_tools_ast(
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
pre_configured_attrs: &[ast::Attribute],
|
||||
sess: &Session,
|
||||
features: &Features,
|
||||
) -> RegisteredTools {
|
||||
let mut registered_tools = RegisteredTools::default();
|
||||
for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) {
|
||||
for meta_item_inner in attr.meta_item_list().unwrap_or_default() {
|
||||
match meta_item_inner.ident() {
|
||||
Some(ident) => {
|
||||
if let Some(old_ident) = registered_tools.replace(ident) {
|
||||
dcx.emit_err(errors::ToolWasAlreadyRegistered {
|
||||
span: ident.span,
|
||||
tool: ident,
|
||||
old_ident_span: old_ident.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
dcx.emit_err(errors::ToolOnlyAcceptsIdentifiers {
|
||||
span: meta_item_inner.span(),
|
||||
tool: sym::register_tool,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(Attribute::Parsed(AttributeKind::RegisterTool(tools, _))) =
|
||||
AttributeParser::parse_limited(
|
||||
sess,
|
||||
pre_configured_attrs,
|
||||
sym::register_tool,
|
||||
DUMMY_SP,
|
||||
DUMMY_NODE_ID,
|
||||
Some(features),
|
||||
)
|
||||
{
|
||||
for tool in tools {
|
||||
if let Some(old_tool) = registered_tools.replace(tool) {
|
||||
dcx.emit_err(errors::ToolWasAlreadyRegistered {
|
||||
span: tool.span,
|
||||
tool,
|
||||
old_ident_span: old_tool.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We implicitly add `rustfmt`, `clippy`, `diagnostic`, `miri` and `rust_analyzer` to known
|
||||
// tools, but it's not an error to register them explicitly.
|
||||
let predefined_tools =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![feature(register_tool)]
|
||||
|
||||
#![register_tool(1)]
|
||||
//~^ ERROR `register_tool` only accepts identifiers
|
||||
//~^ ERROR malformed `register_tool` attribute input
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
error: `register_tool` only accepts identifiers
|
||||
--> $DIR/invalid-tool.rs:3:18
|
||||
error[E0539]: malformed `register_tool` attribute input
|
||||
--> $DIR/invalid-tool.rs:3:1
|
||||
|
|
||||
LL | #![register_tool(1)]
|
||||
| ^ not an identifier
|
||||
| ^^^^^^^^^^^^^^^^^-^^
|
||||
| | |
|
||||
| | expected a valid identifier here
|
||||
| help: must be of the form: `#![register_tool(tool1, tool2, ...)]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(register_tool)]
|
||||
#![register_tool(foo::bar)] //~ ERROR only accepts identifiers
|
||||
#![register_tool(foo::bar)] //~ ERROR malformed `register_tool` attribute input
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
error: `register_tool` only accepts identifiers
|
||||
--> $DIR/nested-disallowed.rs:2:18
|
||||
error[E0539]: malformed `register_tool` attribute input
|
||||
--> $DIR/nested-disallowed.rs:2:1
|
||||
|
|
||||
LL | #![register_tool(foo::bar)]
|
||||
| ^^^^^^^^ not an identifier
|
||||
| ^^^^^^^^^^^^^^^^^--------^^
|
||||
| | |
|
||||
| | expected a valid identifier here
|
||||
| help: must be of the form: `#![register_tool(tool1, tool2, ...)]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
||||
Reference in New Issue
Block a user