Skip to content

Commit 5b57666

Browse files
Introduce the #[diagnostic] attribute namespace
Co-authored-by: est31 <est31@users.noreply.github.com> Co-authored-by: Esteban Kuber <estebank@users.noreply.github.com> Co-authored-by: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
1 parent d150dbb commit 5b57666

15 files changed

+202
-4
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+13
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
218218
}
219219
}
220220
}
221+
if !attr.is_doc_comment()
222+
&& attr.get_normal_item().path.segments.len() == 2
223+
&& attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic
224+
&& !self.features.diagnostic_namespace
225+
{
226+
let msg = "`#[diagnostic]` attribute name space is experimental";
227+
gate_feature_post!(
228+
self,
229+
diagnostic_namespace,
230+
attr.get_normal_item().path.segments[0].ident.span,
231+
msg
232+
);
233+
}
221234

222235
// Emit errors for non-staged-api crates.
223236
if !self.features.staged_api {

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,8 @@ declare_features! (
379379
(active, deprecated_safe, "1.61.0", Some(94978), None),
380380
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
381381
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
382+
/// Allows using the `#[diagnostic]` attribute tool namespace
383+
(active, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(94785), None),
382384
/// Controls errors in trait implementations.
383385
(active, do_not_recommend, "1.67.0", Some(51992), None),
384386
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.

compiler/rustc_lint_defs/src/builtin.rs

+25
Original file line numberDiff line numberDiff line change
@@ -3400,6 +3400,7 @@ declare_lint_pass! {
34003400
UNFULFILLED_LINT_EXPECTATIONS,
34013401
UNINHABITED_STATIC,
34023402
UNKNOWN_CRATE_TYPES,
3403+
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
34033404
UNKNOWN_LINTS,
34043405
UNNAMEABLE_TYPES,
34053406
UNREACHABLE_CODE,
@@ -4380,3 +4381,27 @@ declare_lint! {
43804381
"effective visibility of a type is larger than the area in which it can be named",
43814382
@feature_gate = sym::type_privacy_lints;
43824383
}
4384+
4385+
declare_lint! {
4386+
/// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes.
4387+
///
4388+
/// ### Example
4389+
///
4390+
/// ```rust
4391+
/// #![feature(diagnostic_namespace)]
4392+
/// #[diagnostic::does_not_exist]
4393+
/// struct Foo;
4394+
/// ```
4395+
///
4396+
/// {{produces}}
4397+
///
4398+
/// ### Explanation
4399+
///
4400+
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
4401+
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
4402+
/// consider if you are using an old version of the compiler, and the attribute
4403+
/// is only available in a newer version.
4404+
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
4405+
Warn,
4406+
"unrecognized diagnostic attribute"
4407+
}

compiler/rustc_resolve/src/macros.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
2424
use rustc_middle::middle::stability;
2525
use rustc_middle::ty::RegisteredTools;
2626
use rustc_middle::ty::TyCtxt;
27-
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
27+
use rustc_session::lint::builtin::{
28+
LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
29+
};
2830
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
2931
use rustc_session::lint::BuiltinLintDiagnostics;
3032
use rustc_session::parse::feature_err;
@@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
140142
}
141143
}
142144
}
143-
// We implicitly add `rustfmt` and `clippy` to known tools,
145+
// We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
144146
// but it's not an error to register them explicitly.
145-
let predefined_tools = [sym::clippy, sym::rustfmt];
147+
let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic];
146148
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
147149
registered_tools
148150
}
@@ -595,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
595597
}
596598
}
597599

600+
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
601+
&& path.segments.len() >= 2
602+
&& path.segments[0].ident.name == sym::diagnostic
603+
{
604+
self.tcx.sess.parse_sess.buffer_lint(
605+
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
606+
path.segments[1].span(),
607+
node_id,
608+
"unknown diagnostic attribute",
609+
);
610+
}
611+
598612
Ok((ext, res))
599613
}
600614

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ symbols! {
620620
destruct,
621621
destructuring_assignment,
622622
diagnostic,
623+
diagnostic_namespace,
623624
direct,
624625
discriminant_kind,
625626
discriminant_type,

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
1313
const ENTRY_LIMIT: usize = 900;
1414
// FIXME: The following limits should be reduced eventually.
1515
const ISSUES_ENTRY_LIMIT: usize = 1893;
16-
const ROOT_ENTRY_LIMIT: usize = 870;
16+
const ROOT_ENTRY_LIMIT: usize = 871;
1717

1818
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
1919
"rs", // test source files
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
#![crate_type = "proc-macro"]
4+
5+
extern crate proc_macro;
6+
7+
use proc_macro::TokenStream;
8+
9+
#[proc_macro_attribute]
10+
pub fn diagnostic(i: TokenStream, _: TokenStream) -> TokenStream {
11+
i
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
mod diagnostic {}
4+
5+
macro_rules! diagnostic{
6+
() => {}
7+
}
8+
9+
#[allow(non_upper_case_globals)]
10+
const diagnostic: () = ();
11+
12+
fn main() {
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(diagnostic_namespace)]
2+
// check-pass
3+
// aux-build:proc-macro-helper.rs
4+
5+
extern crate proc_macro_helper;
6+
7+
mod test1 {
8+
use proc_macro_helper::diagnostic;
9+
10+
#[diagnostic]
11+
struct Foo;
12+
13+
}
14+
15+
mod test2 {
16+
mod diagnostic {
17+
pub use proc_macro_helper::diagnostic as on_unimplemented;
18+
}
19+
20+
#[diagnostic::on_unimplemented]
21+
trait Foo {}
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[diagnostic::non_existing_attribute]
2+
//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
3+
//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
4+
pub trait Bar {
5+
}
6+
7+
#[diagnostic::non_existing_attribute(with_option = "foo")]
8+
//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
9+
//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
10+
struct Foo;
11+
12+
fn main() {
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0658]: `#[diagnostic]` attribute name space is experimental
2+
--> $DIR/feature-gate-diagnostic_namespace.rs:1:3
3+
|
4+
LL | #[diagnostic::non_existing_attribute]
5+
| ^^^^^^^^^^
6+
|
7+
= note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
8+
= help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
9+
10+
error[E0658]: `#[diagnostic]` attribute name space is experimental
11+
--> $DIR/feature-gate-diagnostic_namespace.rs:7:3
12+
|
13+
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
14+
| ^^^^^^^^^^
15+
|
16+
= note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
17+
= help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
18+
19+
warning: unknown diagnostic attribute
20+
--> $DIR/feature-gate-diagnostic_namespace.rs:1:15
21+
|
22+
LL | #[diagnostic::non_existing_attribute]
23+
| ^^^^^^^^^^^^^^^^^^^^^^
24+
|
25+
= note: `#[warn(unknown_diagnostic_attributes)]` on by default
26+
27+
warning: unknown diagnostic attribute
28+
--> $DIR/feature-gate-diagnostic_namespace.rs:7:15
29+
|
30+
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
31+
| ^^^^^^^^^^^^^^^^^^^^^^
32+
33+
error: aborting due to 2 previous errors; 2 warnings emitted
34+
35+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(diagnostic_namespace)]
2+
// check-pass
3+
#[diagnostic::non_existing_attribute]
4+
//~^WARN unknown diagnostic attribute
5+
pub trait Bar {
6+
}
7+
8+
#[diagnostic::non_existing_attribute(with_option = "foo")]
9+
//~^WARN unknown diagnostic attribute
10+
struct Foo;
11+
12+
fn main() {
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
warning: unknown diagnostic attribute
2+
--> $DIR/non_existing_attributes_accepted.rs:3:15
3+
|
4+
LL | #[diagnostic::non_existing_attribute]
5+
| ^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(unknown_diagnostic_attributes)]` on by default
8+
9+
warning: unknown diagnostic attribute
10+
--> $DIR/non_existing_attributes_accepted.rs:8:15
11+
|
12+
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
13+
| ^^^^^^^^^^^^^^^^^^^^^^
14+
15+
warning: 2 warnings emitted
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(diagnostic_namespace)]
2+
3+
#[diagnostic]
4+
//~^ERROR cannot find attribute `diagnostic` in this scope
5+
pub struct Bar;
6+
7+
8+
fn main() {
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: cannot find attribute `diagnostic` in this scope
2+
--> $DIR/requires_path.rs:3:3
3+
|
4+
LL | #[diagnostic]
5+
| ^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)