Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/crate_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,50 @@ impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
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
}
}
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ attribute_parsers!(
Combine<FeatureParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<RegisterToolParser>,
Combine<ReprParser>,
Combine<RustcCleanParser>,
Combine<RustcLayoutParser>,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,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)>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl AttributeKind {
ProfilerRuntime => No,
RecursionLimit { .. } => No,
ReexportTestHarnessMain(..) => No,
RegisterTool(..) => No,
Repr { .. } => No,
RustcAbi { .. } => No,
RustcAllocator => No,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::ProfilerRuntime
| AttributeKind::RecursionLimit { .. }
| AttributeKind::ReexportTestHarnessMain(..)
| AttributeKind::RegisterTool(..)
// handled below this loop and elsewhere
| AttributeKind::Repr { .. }
| AttributeKind::RustcAbi { .. }
Expand Down Expand Up @@ -407,8 +408,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| sym::rustc_layout
| sym::rustc_autodiff
// crate-level attrs, are checked below
| sym::feature
| sym::register_tool,
| sym::feature,
..
] => {}
[name, rest@..] => {
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
50 changes: 28 additions & 22 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -15,12 +16,14 @@ use rustc_expand::compile_declarative_macro;
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,
Expand Down Expand Up @@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/tool-attributes/invalid-tool.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(register_tool)]

#![register_tool(1)]
//~^ ERROR `register_tool` only accepts identifiers
//~^ ERROR malformed `register_tool` attribute input

fn main() {}
10 changes: 7 additions & 3 deletions tests/ui/tool-attributes/invalid-tool.stderr
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion tests/ui/tool-attributes/nested-disallowed.rs
Original file line number Diff line number Diff line change
@@ -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() {}
10 changes: 7 additions & 3 deletions tests/ui/tool-attributes/nested-disallowed.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading