Skip to content

Commit 317ec04

Browse files
committed
Auto merge of rust-lang#111780 - weiznich:diagnostic_namespace, r=petrochenkov
Diagnostic namespace This PR implements the basic infrastructure for accepting the `#[diagnostic]` attribute tool namespace as specified in rust-lang/rfcs#3368. Note: This RFC is not merged yet, but it seems like it will be accepted soon. I open this PR early on to get feedback on the actual implementation as soon as possible. This hopefully enables getting at least the diagnostic namespace to stable rust "soon", so that crates do not need to bump their MSRV if we stabilize actual attributes in this namespace. This PR only adds infrastructure accept attributes from this namespace, it does not add any specific attribute. Therefore the compiler will emit a lint warning for each attribute that's actually used. This namespace is added behind a feature flag, so it will be only available on a nightly compiler for now. cc `@estebank` as they've supported me in planing, specifying and implementing this feature.
2 parents b95fd85 + 5b57666 commit 317ec04

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
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
1111
const ENTRY_LIMIT: usize = 900;
1212
// FIXME: The following limits should be reduced eventually.
1313
const ISSUES_ENTRY_LIMIT: usize = 1893;
14-
const ROOT_ENTRY_LIMIT: usize = 870;
14+
const ROOT_ENTRY_LIMIT: usize = 871;
1515

1616
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
1717
"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)