Skip to content
Merged
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
22 changes: 19 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/crate_level.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_feature::AttributeStability;
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
use rustc_session::lint::builtin::{DUPLICATE_TOOLS, UNKNOWN_CRATE_TYPES};
use rustc_span::Symbol;
use rustc_span::edit_distance::find_best_match_for_name_with_substrings;

use super::prelude::*;
use crate::diagnostics::{ToolReserved, UnknownCrateTypes, UnknownCrateTypesSuggestion};
use crate::diagnostics::{
DuplicateTool, ToolReserved, UnknownCrateTypes, UnknownCrateTypesSuggestion,
};

pub(crate) struct CrateNameParser;

Expand Down Expand Up @@ -352,15 +354,29 @@ fn parse_register_tool(
cx.adcx().expected_identifier(path.span());
continue;
};
if !ident.name.can_be_raw() {
cx.adcx().expected_identifier(path.span());
continue;
}

if ident.name == sym::rustc {
cx.should_emit
.emit_err(cx.dcx().create_err(ToolReserved { span: ident.span, tool: ident }));
continue;
}

let mut lint_emitted = false;
for tools in tools.iter_mut() {
tools.insert(ident);
if let Some(old_ident) = tools.replace(ident)
&& !lint_emitted
{
lint_emitted = true;
cx.emit_lint(
DUPLICATE_TOOLS,
DuplicateTool { span: ident.span, tool: ident, old_ident_span: old_ident.span },
ident.span,
);
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,16 @@ pub(crate) struct UnknownExternLangItem {
pub lang_item: Symbol,
}

#[derive(Diagnostic)]
#[diag("duplicate tool `{$tool}` registered")]
pub(crate) struct DuplicateTool {
#[primary_span]
pub(crate) span: Span,
pub(crate) tool: Ident,
#[label("already registered here")]
pub(crate) old_ident_span: Span,
}

#[derive(Diagnostic)]
#[diag("tool `{$tool}` is reserved and cannot be registered")]
pub(crate) struct ToolReserved {
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub mod hardwired {
DEPRECATED_WHERE_CLAUSE_LOCATION,
DUPLICATE_FEATURES,
DUPLICATE_MACRO_ATTRIBUTES,
DUPLICATE_TOOLS,
ELIDED_LIFETIMES_IN_PATHS,
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
EXPORTED_PRIVATE_DEPENDENCIES,
Expand Down Expand Up @@ -5712,3 +5713,29 @@ declare_lint! {
report_in_deps: false,
};
}

declare_lint! {
/// The `duplicate_tools` lint detects duplicate tools found in crate-level
/// [`register_tool` attributes] (including `register_attribute_tool` or `register_lint_tool`).
///
/// [`register_tool` attributes]: https://doc.rust-lang.org/nightly/unstable-book/language-features/register-tool.html
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(register_tool)]
/// #![register_tool(foo)]
/// #![register_tool(foo)]
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Enabling a tool more than once is a no-op.
/// To avoid this warning, remove the second `register_tool()` attribute.
pub DUPLICATE_TOOLS,
Deny,
"duplicate tools found in crate-level `#[register_tools]` directives",
@feature_gate = register_tool;
}
1 change: 1 addition & 0 deletions tests/ui/feature-gates/feature-gate-register_tool.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(duplicate_tools)] //~ WARN [unknown_lints]
#![register_tool(tool)] //~ ERROR the `register_tool` attribute is an experimental feature
#![register_attribute_tool(attr_tool)] //~ ERROR the `register_attribute_tool` attribute is an experimental feature
#![register_lint_tool(lint_tool)] //~ ERROR the `register_lint_tool` attribute is an experimental feature
Expand Down
20 changes: 16 additions & 4 deletions tests/ui/feature-gates/feature-gate-register_tool.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
warning: unknown lint: `duplicate_tools`
--> $DIR/feature-gate-register_tool.rs:1:10
|
LL | #![allow(duplicate_tools)]
| ^^^^^^^^^^^^^^^
|
= note: the `duplicate_tools` lint is unstable
= note: see issue #66079 <https://github.com/rust-lang/rust/issues/66079> for more information
= help: add `#![feature(register_tool)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: `#[warn(unknown_lints)]` on by default

error[E0658]: the `register_tool` attribute is an experimental feature
--> $DIR/feature-gate-register_tool.rs:1:4
--> $DIR/feature-gate-register_tool.rs:2:4
|
LL | #![register_tool(tool)]
| ^^^^^^^^^^^^^
Expand All @@ -9,7 +21,7 @@ LL | #![register_tool(tool)]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: the `register_attribute_tool` attribute is an experimental feature
--> $DIR/feature-gate-register_tool.rs:2:4
--> $DIR/feature-gate-register_tool.rs:3:4
|
LL | #![register_attribute_tool(attr_tool)]
| ^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -19,7 +31,7 @@ LL | #![register_attribute_tool(attr_tool)]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: the `register_lint_tool` attribute is an experimental feature
--> $DIR/feature-gate-register_tool.rs:3:4
--> $DIR/feature-gate-register_tool.rs:4:4
|
LL | #![register_lint_tool(lint_tool)]
| ^^^^^^^^^^^^^^^^^^
Expand All @@ -28,6 +40,6 @@ LL | #![register_lint_tool(lint_tool)]
= help: add `#![feature(register_tool)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 3 previous errors
error: aborting due to 3 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0658`.
2 changes: 2 additions & 0 deletions tests/ui/tool-attributes/auxiliary/use_tool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#![feature(register_tool)]
#![register_tool(foo)]
13 changes: 13 additions & 0 deletions tests/ui/tool-attributes/crate-attr-dup-tool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ check-pass
//@ compile-flags: -Z crate-attr=feature(register_tool) -Z crate-attr=register_tool(foo)
//@ compile-flags: -Z crate-attr=register_attribute_tool(bar) -Z crate-attr=register_lint_tool(baz)
//@ compile-flags: -A duplicate_features -A duplicate_tools
#![feature(register_tool)]
#![register_tool(foo)]
#![register_attribute_tool(bar)]
#![register_lint_tool(baz)]

#[foo::foo]
#[bar::bar]
#[allow(foo::baz, baz::baz)]
fn main() {}
10 changes: 10 additions & 0 deletions tests/ui/tool-attributes/cross-crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ aux-build: use_tool.rs

// `use_tool` references tool "foo", and we want to check that it has no impact on this crate.
extern crate use_tool;

#[foo::bar] //~ ERROR cannot find module or crate `foo` in this scope
#[allow(foo::baz)] //~ ERROR unknown tool name `foo`
//~| ERROR unknown tool name `foo`
//~| ERROR unknown tool name `foo`
fn main() {}
36 changes: 36 additions & 0 deletions tests/ui/tool-attributes/cross-crate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz`
--> $DIR/cross-crate.rs:7:9
|
LL | #[allow(foo::baz)]
| ^^^
|
= help: add `#![register_tool(foo)]` to the crate root

error[E0433]: cannot find module or crate `foo` in this scope
--> $DIR/cross-crate.rs:6:3
|
LL | #[foo::bar]
| ^^^ use of unresolved module or unlinked crate `foo`

error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz`
--> $DIR/cross-crate.rs:7:9
|
LL | #[allow(foo::baz)]
| ^^^
|
= help: add `#![register_tool(foo)]` to the crate root
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz`
--> $DIR/cross-crate.rs:7:9
|
LL | #[allow(foo::baz)]
| ^^^
|
= help: add `#![register_tool(foo)]` to the crate root
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0433, E0710.
For more information about an error, try `rustc --explain E0433`.
11 changes: 6 additions & 5 deletions tests/ui/tool-attributes/duplicate-tool.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add such a test using -Zcrate-attr=register_tool(..) -Zallow(duplicate_tools) (whatever the precise syntax is) with a crate level attribute introducing the same tool?

Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
//@ check-pass
#![feature(register_tool)]
#![warn(duplicate_tools)]
// Register a tool multiple times is okay.
#![register_tool(foo)]
#![register_tool(foo)]
#![register_tool(foo)] //~ WARN [duplicate_tools]
#![register_tool(bar)]
#![register_attribute_tool(bar)]
#![register_attribute_tool(bar)] //~ WARN [duplicate_tools]
#![register_tool(baz)]
#![register_lint_tool(baz)]
#![register_attribute_tool(qux)]
#![register_lint_tool(baz)] //~ WARN [duplicate_tools]
#![register_attribute_tool(qux)]
#![register_attribute_tool(qux)] //~ WARN [duplicate_tools]
#![register_lint_tool(quux)]
#![register_lint_tool(quux)]
#![register_lint_tool(quux)] //~ WARN [duplicate_tools]

fn main() {}
48 changes: 48 additions & 0 deletions tests/ui/tool-attributes/duplicate-tool.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
warning: duplicate tool `foo` registered
--> $DIR/duplicate-tool.rs:6:18
|
LL | #![register_tool(foo)]
| --- already registered here
LL | #![register_tool(foo)]
| ^^^
|
note: the lint level is defined here
--> $DIR/duplicate-tool.rs:3:9
|
LL | #![warn(duplicate_tools)]
| ^^^^^^^^^^^^^^^

warning: duplicate tool `bar` registered
--> $DIR/duplicate-tool.rs:8:28
|
LL | #![register_tool(bar)]
| --- already registered here
LL | #![register_attribute_tool(bar)]
| ^^^

warning: duplicate tool `baz` registered
--> $DIR/duplicate-tool.rs:10:23
|
LL | #![register_tool(baz)]
| --- already registered here
LL | #![register_lint_tool(baz)]
| ^^^

warning: duplicate tool `qux` registered
--> $DIR/duplicate-tool.rs:12:28
|
LL | #![register_attribute_tool(qux)]
| --- already registered here
LL | #![register_attribute_tool(qux)]
| ^^^

warning: duplicate tool `quux` registered
--> $DIR/duplicate-tool.rs:14:23
|
LL | #![register_lint_tool(quux)]
| ---- already registered here
LL | #![register_lint_tool(quux)]
| ^^^^

warning: 5 warnings emitted

19 changes: 19 additions & 0 deletions tests/ui/tool-attributes/invalid-tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,24 @@

#![register_tool(1)]
//~^ ERROR malformed `register_tool` attribute input
#![register_tool(_)]
//~^ ERROR expected identifier, found reserved identifier `_`
//~| ERROR expected identifier, found reserved identifier `_`
//~| ERROR expected identifier, found reserved identifier `_`
//~| ERROR malformed `register_tool` attribute input

// Special path keywords cannot be used.
#![register_tool(crate)]
//~^ ERROR malformed `register_tool` attribute input
#![register_tool(self)]
//~^ ERROR malformed `register_tool` attribute input
#![register_tool(Self)]
//~^ ERROR malformed `register_tool` attribute input
#![register_tool(super)]
//~^ ERROR malformed `register_tool` attribute input

// These are okay
#![register_tool(r#type)]
#![register_tool(铁锈)]

fn main() {}
Loading
Loading