Skip to content

Commit

Permalink
Introduce the #[diagnostic] attribute namespace
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
weiznich and petrochenkov committed Jul 28, 2023
1 parent d150dbb commit 5b57666
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 4 deletions.
13 changes: 13 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
if !self.features.staged_api {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ declare_features! (
(active, deprecated_safe, "1.61.0", Some(94978), None),
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
(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.
(active, do_not_recommend, "1.67.0", Some(51992), None),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3400,6 +3400,7 @@ declare_lint_pass! {
UNFULFILLED_LINT_EXPECTATIONS,
UNINHABITED_STATIC,
UNKNOWN_CRATE_TYPES,
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
UNKNOWN_LINTS,
UNNAMEABLE_TYPES,
UNREACHABLE_CODE,
Expand Down Expand Up @@ -4380,3 +4381,27 @@ declare_lint! {
"effective visibility of a type is larger than the area in which it can be named",
@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"
}
20 changes: 17 additions & 3 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
use rustc_middle::middle::stability;
use rustc_middle::ty::RegisteredTools;
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::BuiltinLintDiagnostics;
use rustc_session::parse::feature_err;
Expand Down Expand Up @@ -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.
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
}
Expand Down Expand Up @@ -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))
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ symbols! {
destruct,
destructuring_assignment,
diagnostic,
diagnostic_namespace,
direct,
discriminant_kind,
discriminant_type,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/tidy/src/ui_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
const ENTRY_LIMIT: usize = 900;
// FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: usize = 1893;
const ROOT_ENTRY_LIMIT: usize = 870;
const ROOT_ENTRY_LIMIT: usize = 871;

const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/diagnostic_namespace/auxiliary/proc-macro-helper.rs
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// check-pass

mod diagnostic {}

macro_rules! diagnostic{
() => {}
}

#[allow(non_upper_case_globals)]
const diagnostic: () = ();

fn main() {
}
24 changes: 24 additions & 0 deletions tests/ui/diagnostic_namespace/existing_proc_macros.rs
Original file line number Diff line number Diff line change
@@ -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() {}
13 changes: 13 additions & 0 deletions tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs
Original file line number Diff line number Diff line change
@@ -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() {
}
Original file line number Diff line number Diff line change
@@ -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`.
13 changes: 13 additions & 0 deletions tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs
Original file line number Diff line number Diff line change
@@ -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() {
}
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions tests/ui/diagnostic_namespace/requires_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![feature(diagnostic_namespace)]

#[diagnostic]
//~^ERROR cannot find attribute `diagnostic` in this scope
pub struct Bar;


fn main() {
}
8 changes: 8 additions & 0 deletions tests/ui/diagnostic_namespace/requires_path.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 5b57666

Please sign in to comment.