gate rustc_on_unimplemented under rustc_attrs
This commit is contained in:
parent
e4931eaaa3
commit
1c7595fd0f
17 changed files with 34 additions and 190 deletions
|
@ -1,154 +0,0 @@
|
||||||
# `on_unimplemented`
|
|
||||||
|
|
||||||
The tracking issue for this feature is: [#29628]
|
|
||||||
|
|
||||||
[#29628]: https://github.com/rust-lang/rust/issues/29628
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
The `on_unimplemented` feature provides the `#[rustc_on_unimplemented]`
|
|
||||||
attribute, which allows trait definitions to add specialized notes to error
|
|
||||||
messages when an implementation was expected but not found. You can refer
|
|
||||||
to the trait's generic arguments by name and to the resolved type using
|
|
||||||
`Self`.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```rust,compile_fail
|
|
||||||
#![feature(on_unimplemented)]
|
|
||||||
|
|
||||||
#[rustc_on_unimplemented="an iterator over elements of type `{A}` \
|
|
||||||
cannot be built from a collection of type `{Self}`"]
|
|
||||||
trait MyIterator<A> {
|
|
||||||
fn next(&mut self) -> A;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iterate_chars<I: MyIterator<char>>(i: I) {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
iterate_chars(&[1, 2, 3][..]);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
When the user compiles this, they will see the following;
|
|
||||||
|
|
||||||
```txt
|
|
||||||
error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
|
|
||||||
--> <anon>:14:5
|
|
||||||
|
|
|
||||||
14 | iterate_chars(&[1, 2, 3][..]);
|
|
||||||
| ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
|
|
||||||
|
|
|
||||||
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
|
||||||
= note: required by `iterate_chars`
|
|
||||||
```
|
|
||||||
|
|
||||||
`on_unimplemented` also supports advanced filtering for better targeting
|
|
||||||
of messages, as well as modifying specific parts of the error message. You
|
|
||||||
target the text of:
|
|
||||||
|
|
||||||
- the main error message (`message`)
|
|
||||||
- the label (`label`)
|
|
||||||
- an extra note (`note`)
|
|
||||||
|
|
||||||
For example, the following attribute
|
|
||||||
|
|
||||||
```rust,compile_fail
|
|
||||||
#[rustc_on_unimplemented(
|
|
||||||
message="message",
|
|
||||||
label="label",
|
|
||||||
note="note"
|
|
||||||
)]
|
|
||||||
trait MyIterator<A> {
|
|
||||||
fn next(&mut self) -> A;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Would generate the following output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
error[E0277]: message
|
|
||||||
--> <anon>:14:5
|
|
||||||
|
|
|
||||||
14 | iterate_chars(&[1, 2, 3][..]);
|
|
||||||
| ^^^^^^^^^^^^^ label
|
|
||||||
|
|
|
||||||
= note: note
|
|
||||||
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
|
||||||
= note: required by `iterate_chars`
|
|
||||||
```
|
|
||||||
|
|
||||||
To allow more targeted error messages, it is possible to filter the
|
|
||||||
application of these fields based on a variety of attributes when using
|
|
||||||
`on`:
|
|
||||||
|
|
||||||
- `crate_local`: whether the code causing the trait bound to not be
|
|
||||||
fulfilled is part of the user's crate. This is used to avoid suggesting
|
|
||||||
code changes that would require modifying a dependency.
|
|
||||||
- Any of the generic arguments that can be substituted in the text can be
|
|
||||||
referred by name as well for filtering, like `Rhs="i32"`, except for
|
|
||||||
`Self`.
|
|
||||||
- `_Self`: to filter only on a particular calculated trait resolution, like
|
|
||||||
`Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
|
|
||||||
keyword which cannot appear in attributes.
|
|
||||||
- `direct`: user-specified rather than derived obligation.
|
|
||||||
- `from_method`: usable both as boolean (whether the flag is present, like
|
|
||||||
`crate_local`) or matching against a particular method. Currently used
|
|
||||||
for `try`.
|
|
||||||
- `from_desugaring`: usable both as boolean (whether the flag is present)
|
|
||||||
or matching against a particular desugaring. The desugaring is identified
|
|
||||||
with its variant name in the `DesugaringKind` enum.
|
|
||||||
|
|
||||||
For example, the `Iterator` trait can be annotated in the following way:
|
|
||||||
|
|
||||||
```rust,compile_fail
|
|
||||||
#[rustc_on_unimplemented(
|
|
||||||
on(
|
|
||||||
_Self="&str",
|
|
||||||
note="call `.chars()` or `.as_bytes()` on `{Self}"
|
|
||||||
),
|
|
||||||
message="`{Self}` is not an iterator",
|
|
||||||
label="`{Self}` is not an iterator",
|
|
||||||
note="maybe try calling `.iter()` or a similar method"
|
|
||||||
)]
|
|
||||||
pub trait Iterator {}
|
|
||||||
```
|
|
||||||
|
|
||||||
Which would produce the following outputs:
|
|
||||||
|
|
||||||
```text
|
|
||||||
error[E0277]: `Foo` is not an iterator
|
|
||||||
--> src/main.rs:4:16
|
|
||||||
|
|
|
||||||
4 | for foo in Foo {}
|
|
||||||
| ^^^ `Foo` is not an iterator
|
|
||||||
|
|
|
||||||
= note: maybe try calling `.iter()` or a similar method
|
|
||||||
= help: the trait `std::iter::Iterator` is not implemented for `Foo`
|
|
||||||
= note: required by `std::iter::IntoIterator::into_iter`
|
|
||||||
|
|
||||||
error[E0277]: `&str` is not an iterator
|
|
||||||
--> src/main.rs:5:16
|
|
||||||
|
|
|
||||||
5 | for foo in "" {}
|
|
||||||
| ^^ `&str` is not an iterator
|
|
||||||
|
|
|
||||||
= note: call `.chars()` or `.bytes() on `&str`
|
|
||||||
= help: the trait `std::iter::Iterator` is not implemented for `&str`
|
|
||||||
= note: required by `std::iter::IntoIterator::into_iter`
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need to filter on multiple attributes, you can use `all`, `any` or
|
|
||||||
`not` in the following way:
|
|
||||||
|
|
||||||
```rust,compile_fail
|
|
||||||
#[rustc_on_unimplemented(
|
|
||||||
on(
|
|
||||||
all(_Self="&str", T="std::string::String"),
|
|
||||||
note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
pub trait From<T>: Sized { /* ... */ }
|
|
||||||
```
|
|
|
@ -116,7 +116,7 @@
|
||||||
#![feature(unsize)]
|
#![feature(unsize)]
|
||||||
#![feature(unsized_locals)]
|
#![feature(unsized_locals)]
|
||||||
#![feature(allocator_internals)]
|
#![feature(allocator_internals)]
|
||||||
#![feature(on_unimplemented)]
|
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||||
#![feature(rustc_const_unstable)]
|
#![feature(rustc_const_unstable)]
|
||||||
#![feature(slice_partition_dedup)]
|
#![feature(slice_partition_dedup)]
|
||||||
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
|
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(exhaustive_patterns)]
|
#![feature(exhaustive_patterns)]
|
||||||
#![feature(no_core)]
|
#![feature(no_core)]
|
||||||
#![feature(on_unimplemented)]
|
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
#![feature(prelude_import)]
|
#![feature(prelude_import)]
|
||||||
#![feature(repr_simd, platform_intrinsics)]
|
#![feature(repr_simd, platform_intrinsics)]
|
||||||
|
|
|
@ -607,7 +607,7 @@ position that needs that trait. For example, when the following code is
|
||||||
compiled:
|
compiled:
|
||||||
|
|
||||||
```compile_fail
|
```compile_fail
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
fn foo<T: Index<u8>>(x: T){}
|
fn foo<T: Index<u8>>(x: T){}
|
||||||
|
|
||||||
|
@ -639,7 +639,7 @@ position that needs that trait. For example, when the following code is
|
||||||
compiled:
|
compiled:
|
||||||
|
|
||||||
```compile_fail
|
```compile_fail
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
fn foo<T: Index<u8>>(x: T){}
|
fn foo<T: Index<u8>>(x: T){}
|
||||||
|
|
||||||
|
@ -669,7 +669,7 @@ position that needs that trait. For example, when the following code is
|
||||||
compiled:
|
compiled:
|
||||||
|
|
||||||
```compile_fail
|
```compile_fail
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
fn foo<T: Index<u8>>(x: T){}
|
fn foo<T: Index<u8>>(x: T){}
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,7 @@
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||||
#![feature(on_unimplemented)]
|
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(panic_internals)]
|
#![feature(panic_internals)]
|
||||||
|
|
|
@ -134,9 +134,6 @@ declare_features! (
|
||||||
/// Allows using `rustc_*` attributes (RFC 572).
|
/// Allows using `rustc_*` attributes (RFC 572).
|
||||||
(active, rustc_attrs, "1.0.0", Some(29642), None),
|
(active, rustc_attrs, "1.0.0", Some(29642), None),
|
||||||
|
|
||||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
|
||||||
(active, on_unimplemented, "1.0.0", Some(29628), None),
|
|
||||||
|
|
||||||
/// Allows using the `box $expr` syntax.
|
/// Allows using the `box $expr` syntax.
|
||||||
(active, box_syntax, "1.0.0", Some(49733), None),
|
(active, box_syntax, "1.0.0", Some(49733), None),
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ macro_rules! experimental {
|
||||||
}
|
}
|
||||||
|
|
||||||
const IMPL_DETAIL: &str = "internal implementation detail";
|
const IMPL_DETAIL: &str = "internal implementation detail";
|
||||||
const INTERAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
||||||
|
|
||||||
pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
|
pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
|
||||||
|
|
||||||
|
@ -418,14 +418,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
|
linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
|
||||||
"the `linkage` attribute is experimental and not portable across platforms",
|
"the `linkage` attribute is experimental and not portable across platforms",
|
||||||
),
|
),
|
||||||
rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE),
|
rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERNAL_UNSTABLE),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes, Macro related:
|
// Internal attributes, Macro related:
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL),
|
rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERAL_UNSTABLE),
|
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_macro_transparency, Whitelisted,
|
rustc_macro_transparency, Whitelisted,
|
||||||
template!(NameValueStr: "transparent|semitransparent|opaque"),
|
template!(NameValueStr: "transparent|semitransparent|opaque"),
|
||||||
|
@ -436,17 +436,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// Internal attributes, Diagnostics related:
|
// Internal attributes, Diagnostics related:
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
gated!(
|
rustc_attr!(
|
||||||
rustc_on_unimplemented, Whitelisted,
|
rustc_on_unimplemented, Whitelisted,
|
||||||
template!(
|
template!(
|
||||||
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
|
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
|
||||||
NameValueStr: "message"
|
NameValueStr: "message"
|
||||||
),
|
),
|
||||||
on_unimplemented,
|
INTERNAL_UNSTABLE
|
||||||
experimental!(rustc_on_unimplemented),
|
|
||||||
),
|
),
|
||||||
// Whitelists "identity-like" conversion methods to suggest on type mismatch.
|
// Whitelists "identity-like" conversion methods to suggest on type mismatch.
|
||||||
rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE),
|
rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERNAL_UNSTABLE),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes, Const related:
|
// Internal attributes, Const related:
|
||||||
|
@ -454,7 +453,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
|
|
||||||
rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL),
|
rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL),
|
rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE),
|
rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERNAL_UNSTABLE),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes, Layout related:
|
// Internal attributes, Layout related:
|
||||||
|
|
|
@ -99,6 +99,9 @@ declare_features! (
|
||||||
/// + `__register_diagnostic`
|
/// + `__register_diagnostic`
|
||||||
/// +`__build_diagnostic_array`
|
/// +`__build_diagnostic_array`
|
||||||
(removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
|
(removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
|
||||||
|
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||||
|
/// (Moved to `rustc_attrs`.)
|
||||||
|
(removed, on_unimplemented, "1.40.0", None, None, None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: removed features
|
// feature-group-end: removed features
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// revisions: cfail1 cfail2
|
// revisions: cfail1 cfail2
|
||||||
// build-pass (FIXME(62277): could be check-pass?)
|
// build-pass (FIXME(62277): could be check-pass?)
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
#![deny(unused_attributes)]
|
#![deny(unused_attributes)]
|
||||||
|
|
||||||
#[rustc_on_unimplemented = "invalid"]
|
#[rustc_on_unimplemented = "invalid"]
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Test that `#[rustc_on_unimplemented]` is gated by `on_unimplemented` feature
|
|
||||||
// gate.
|
|
||||||
|
|
||||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
|
||||||
//~^ ERROR the `#[rustc_on_unimplemented]` attribute is an experimental feature
|
|
||||||
trait Foo<Bar>
|
|
||||||
{}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,6 +1,6 @@
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// access to the variable, whether that mutable access be used
|
// access to the variable, whether that mutable access be used
|
||||||
// for direct assignment or for taking mutable ref. Issue #6801.
|
// for direct assignment or for taking mutable ref. Issue #6801.
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_on_unimplemented(
|
#[rustc_on_unimplemented(
|
||||||
message="the message"
|
message="the message"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
|
||||||
|
|
||||||
|
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||||
|
//~^ ERROR this is an internal attribute that will never be stable
|
||||||
|
trait Foo<Bar>
|
||||||
|
{}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,11 +1,11 @@
|
||||||
error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature
|
error[E0658]: this is an internal attribute that will never be stable
|
||||||
--> $DIR/feature-gate-on-unimplemented.rs:4:1
|
--> $DIR/feature-gate-on-unimplemented.rs:3:1
|
||||||
|
|
|
|
||||||
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rust/issues/29628
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29642
|
||||||
= help: add `#![feature(on_unimplemented)]` to the crate attributes to enable
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Test if the on_unimplemented message override works
|
// Test if the on_unimplemented message override works
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
|
||||||
struct Foo<T>(T);
|
struct Foo<T>(T);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Test if the on_unimplemented message override works
|
// Test if the on_unimplemented message override works
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
|
||||||
#[rustc_on_unimplemented = "invalid"]
|
#[rustc_on_unimplemented = "invalid"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![feature(on_unimplemented)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
pub mod Bar {
|
pub mod Bar {
|
||||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{Foo}`"]
|
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{Foo}`"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue