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>
This commit is contained in:
parent
d150dbb067
commit
5b576665e5
15 changed files with 202 additions and 4 deletions
|
@ -218,6 +218,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !attr.is_doc_comment()
|
||||||
|
&& attr.get_normal_item().path.segments.len() == 2
|
||||||
|
&& attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic
|
||||||
|
&& !self.features.diagnostic_namespace
|
||||||
|
{
|
||||||
|
let msg = "`#[diagnostic]` attribute name space is experimental";
|
||||||
|
gate_feature_post!(
|
||||||
|
self,
|
||||||
|
diagnostic_namespace,
|
||||||
|
attr.get_normal_item().path.segments[0].ident.span,
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Emit errors for non-staged-api crates.
|
// Emit errors for non-staged-api crates.
|
||||||
if !self.features.staged_api {
|
if !self.features.staged_api {
|
||||||
|
|
|
@ -379,6 +379,8 @@ declare_features! (
|
||||||
(active, deprecated_safe, "1.61.0", Some(94978), None),
|
(active, deprecated_safe, "1.61.0", Some(94978), None),
|
||||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||||
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
||||||
|
/// Allows using the `#[diagnostic]` attribute tool namespace
|
||||||
|
(active, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(94785), None),
|
||||||
/// Controls errors in trait implementations.
|
/// Controls errors in trait implementations.
|
||||||
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
||||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||||
|
|
|
@ -3400,6 +3400,7 @@ declare_lint_pass! {
|
||||||
UNFULFILLED_LINT_EXPECTATIONS,
|
UNFULFILLED_LINT_EXPECTATIONS,
|
||||||
UNINHABITED_STATIC,
|
UNINHABITED_STATIC,
|
||||||
UNKNOWN_CRATE_TYPES,
|
UNKNOWN_CRATE_TYPES,
|
||||||
|
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||||
UNKNOWN_LINTS,
|
UNKNOWN_LINTS,
|
||||||
UNNAMEABLE_TYPES,
|
UNNAMEABLE_TYPES,
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
|
@ -4380,3 +4381,27 @@ declare_lint! {
|
||||||
"effective visibility of a type is larger than the area in which it can be named",
|
"effective visibility of a type is larger than the area in which it can be named",
|
||||||
@feature_gate = sym::type_privacy_lints;
|
@feature_gate = sym::type_privacy_lints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(diagnostic_namespace)]
|
||||||
|
/// #[diagnostic::does_not_exist]
|
||||||
|
/// struct Foo;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
|
||||||
|
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
|
||||||
|
/// consider if you are using an old version of the compiler, and the attribute
|
||||||
|
/// is only available in a newer version.
|
||||||
|
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||||
|
Warn,
|
||||||
|
"unrecognized diagnostic attribute"
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::RegisteredTools;
|
use rustc_middle::ty::RegisteredTools;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
|
use rustc_session::lint::builtin::{
|
||||||
|
LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||||
|
};
|
||||||
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
|
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We implicitly add `rustfmt` and `clippy` to known tools,
|
// We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
|
||||||
// but it's not an error to register them explicitly.
|
// but it's not an error to register them explicitly.
|
||||||
let predefined_tools = [sym::clippy, sym::rustfmt];
|
let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic];
|
||||||
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
|
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
|
||||||
registered_tools
|
registered_tools
|
||||||
}
|
}
|
||||||
|
@ -595,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
|
||||||
|
&& path.segments.len() >= 2
|
||||||
|
&& path.segments[0].ident.name == sym::diagnostic
|
||||||
|
{
|
||||||
|
self.tcx.sess.parse_sess.buffer_lint(
|
||||||
|
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||||
|
path.segments[1].span(),
|
||||||
|
node_id,
|
||||||
|
"unknown diagnostic attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Ok((ext, res))
|
Ok((ext, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -620,6 +620,7 @@ symbols! {
|
||||||
destruct,
|
destruct,
|
||||||
destructuring_assignment,
|
destructuring_assignment,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
|
diagnostic_namespace,
|
||||||
direct,
|
direct,
|
||||||
discriminant_kind,
|
discriminant_kind,
|
||||||
discriminant_type,
|
discriminant_type,
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
|
||||||
const ENTRY_LIMIT: usize = 900;
|
const ENTRY_LIMIT: usize = 900;
|
||||||
// FIXME: The following limits should be reduced eventually.
|
// FIXME: The following limits should be reduced eventually.
|
||||||
const ISSUES_ENTRY_LIMIT: usize = 1893;
|
const ISSUES_ENTRY_LIMIT: usize = 1893;
|
||||||
const ROOT_ENTRY_LIMIT: usize = 870;
|
const ROOT_ENTRY_LIMIT: usize = 871;
|
||||||
|
|
||||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||||
"rs", // test source files
|
"rs", // test source files
|
||||||
|
|
12
tests/ui/diagnostic_namespace/auxiliary/proc-macro-helper.rs
Normal file
12
tests/ui/diagnostic_namespace/auxiliary/proc-macro-helper.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn diagnostic(i: TokenStream, _: TokenStream) -> TokenStream {
|
||||||
|
i
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
mod diagnostic {}
|
||||||
|
|
||||||
|
macro_rules! diagnostic{
|
||||||
|
() => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
const diagnostic: () = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
24
tests/ui/diagnostic_namespace/existing_proc_macros.rs
Normal file
24
tests/ui/diagnostic_namespace/existing_proc_macros.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#![feature(diagnostic_namespace)]
|
||||||
|
// check-pass
|
||||||
|
// aux-build:proc-macro-helper.rs
|
||||||
|
|
||||||
|
extern crate proc_macro_helper;
|
||||||
|
|
||||||
|
mod test1 {
|
||||||
|
use proc_macro_helper::diagnostic;
|
||||||
|
|
||||||
|
#[diagnostic]
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test2 {
|
||||||
|
mod diagnostic {
|
||||||
|
pub use proc_macro_helper::diagnostic as on_unimplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[diagnostic::on_unimplemented]
|
||||||
|
trait Foo {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#[diagnostic::non_existing_attribute]
|
||||||
|
//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
|
||||||
|
//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
|
||||||
|
pub trait Bar {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[diagnostic::non_existing_attribute(with_option = "foo")]
|
||||||
|
//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
|
||||||
|
//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
error[E0658]: `#[diagnostic]` attribute name space is experimental
|
||||||
|
--> $DIR/feature-gate-diagnostic_namespace.rs:1:3
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
|
||||||
|
= help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: `#[diagnostic]` attribute name space is experimental
|
||||||
|
--> $DIR/feature-gate-diagnostic_namespace.rs:7:3
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
|
||||||
|
= help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: unknown diagnostic attribute
|
||||||
|
--> $DIR/feature-gate-diagnostic_namespace.rs:1:15
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unknown_diagnostic_attributes)]` on by default
|
||||||
|
|
||||||
|
warning: unknown diagnostic attribute
|
||||||
|
--> $DIR/feature-gate-diagnostic_namespace.rs:7:15
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 2 warnings emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(diagnostic_namespace)]
|
||||||
|
// check-pass
|
||||||
|
#[diagnostic::non_existing_attribute]
|
||||||
|
//~^WARN unknown diagnostic attribute
|
||||||
|
pub trait Bar {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[diagnostic::non_existing_attribute(with_option = "foo")]
|
||||||
|
//~^WARN unknown diagnostic attribute
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
warning: unknown diagnostic attribute
|
||||||
|
--> $DIR/non_existing_attributes_accepted.rs:3:15
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unknown_diagnostic_attributes)]` on by default
|
||||||
|
|
||||||
|
warning: unknown diagnostic attribute
|
||||||
|
--> $DIR/non_existing_attributes_accepted.rs:8:15
|
||||||
|
|
|
||||||
|
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: 2 warnings emitted
|
||||||
|
|
9
tests/ui/diagnostic_namespace/requires_path.rs
Normal file
9
tests/ui/diagnostic_namespace/requires_path.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#![feature(diagnostic_namespace)]
|
||||||
|
|
||||||
|
#[diagnostic]
|
||||||
|
//~^ERROR cannot find attribute `diagnostic` in this scope
|
||||||
|
pub struct Bar;
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
8
tests/ui/diagnostic_namespace/requires_path.stderr
Normal file
8
tests/ui/diagnostic_namespace/requires_path.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
error: cannot find attribute `diagnostic` in this scope
|
||||||
|
--> $DIR/requires_path.rs:3:3
|
||||||
|
|
|
||||||
|
LL | #[diagnostic]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue