Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString {
// if the integer type has been resolved, to allow targeting all integers.
// `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet,
// from the `Display` impl of `InferTy` to be precise.
// `"{union|enum|struct}"` is used as a special selector for ADTs.
//
// Don't try to format these later!
Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => {
LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}")))
}
Position::ArgumentNamed(
arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))),

Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3460,13 +3460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?;

let can_derive = match diagnostic_name {
sym::Copy | sym::Clone => true,
_ if adt.is_union() => false,
sym::Default
| sym::Eq
| sym::PartialEq
| sym::Ord
| sym::PartialOrd
| sym::Clone
| sym::Copy
| sym::Hash
| sym::Debug => true,
_ => false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}

if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
crate_local = true;
if let Some(adt) = self_ty.ty_adt_def() {
if adt.did().is_local() {
crate_local = true;
}
self_types.push(format!("{{{}}}", adt.descr()))
}

// Allow targeting all integers using `{integral}`, even if the exact type was resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4037,12 +4037,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
_ => return false,
};
let is_derivable_trait = match diagnostic_name {
sym::Default => !adt.is_enum(),
sym::Copy | sym::Clone => true,
_ if adt.is_union() => false,
sym::PartialEq | sym::PartialOrd => {
let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
trait_pred.skip_binder().self_ty() == rhs_ty
}
sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
sym::Eq | sym::Ord | sym::Hash | sym::Debug | sym::Default => true,
_ => false,
};
is_derivable_trait &&
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,9 +1037,10 @@ impl Display for Arguments<'_> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
on(
crate_local,
all(crate_local, not(Self = "{union}")),
Comment thread
malezjaa marked this conversation as resolved.
note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`"
),
on(all(crate_local, Self = "{union}"), note = "manually `impl {This} for {Self}`"),
on(
from_desugaring = "FormatLiteral",
label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ impl Bar for i32 {}
// cannot use special rustc_on_unimplement symbols
// in the format string
#[diagnostic::on_unimplemented(
message = "{from_desugaring}{direct}{cause}{integral}{integer}",
message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
//~^WARN there is no parameter `from_desugaring` on trait `Baz`
//~|WARN there is no parameter `direct` on trait `Baz`
//~|WARN there is no parameter `cause` on trait `Baz`
//~|WARN there is no parameter `integral` on trait `Baz`
//~|WARN there is no parameter `integer` on trait `Baz`
//~|WARN there is no parameter `r#struct` on trait `Baz`
//~|WARN there is no parameter `r#enum` on trait `Baz`
//~|WARN there is no parameter `union` on trait `Baz`
label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
//~^WARN there is no parameter `float` on trait `Baz`
//~|WARN there is no parameter `_Self` on trait `Baz`
Expand All @@ -52,5 +55,5 @@ fn main() {
takes_bar(());
//~^ERROR the trait bound `(): Bar` is not satisfied
takes_baz(());
//~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}
//~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl
warning: there is no parameter `from_desugaring` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:17
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
Expand All @@ -18,77 +18,101 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
warning: there is no parameter `direct` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:34
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `cause` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:42
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `integral` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:49
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `integer` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:59
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `r#struct` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:68
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `r#enum` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:76
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `union` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:82
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
| ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `float` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:15
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:15
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `_Self` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:22
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:22
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `crate_local` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:29
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:29
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `Trait` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:42
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:42
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `ItemContext` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:49
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:49
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: there is no parameter `This` on trait `Baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:62
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:62
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
| ^^^^
Expand Down Expand Up @@ -129,7 +153,7 @@ LL | #[diagnostic::on_unimplemented = "Message"]
= help: only `message`, `note` and `label` are allowed as options

error[E0277]: trait has `()` and `i32` as params
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:15
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15
|
LL | takes_foo(());
| --------- ^^ trait has `()` and `i32` as params
Expand All @@ -144,13 +168,13 @@ help: this trait has no implementations, consider adding one
LL | trait Foo<T> {}
| ^^^^^^^^^^^^
note: required by a bound in `takes_foo`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:45:22
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:48:22
|
LL | fn takes_foo(_: impl Foo<i32>) {}
| ^^^^^^^^ required by this bound in `takes_foo`

error[E0277]: the trait bound `(): Bar` is not satisfied
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:15
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:15
|
LL | takes_bar(());
| --------- ^^ the trait `Bar` is not implemented for `()`
Expand All @@ -163,13 +187,13 @@ help: the trait `Bar` is implemented for `i32`
LL | impl Bar for i32 {}
| ^^^^^^^^^^^^^^^^
note: required by a bound in `takes_bar`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:22
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:22
|
LL | fn takes_bar(_: impl Bar) {}
| ^^^ required by this bound in `takes_bar`

error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:15
error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:15
|
LL | takes_baz(());
| --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This}
Expand All @@ -178,16 +202,16 @@ LL | takes_baz(());
|
= help: the trait `Baz` is not implemented for `()`
help: this trait has no implementations, consider adding one
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:43:1
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:1
|
LL | trait Baz {}
| ^^^^^^^^^
note: required by a bound in `takes_baz`
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:47:22
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:22
|
LL | fn takes_baz(_: impl Baz) {}
| ^^^ required by this bound in `takes_baz`

error: aborting due to 3 previous errors; 16 warnings emitted
error: aborting due to 3 previous errors; 19 warnings emitted

For more information about this error, try `rustc --explain E0277`.
30 changes: 30 additions & 0 deletions tests/ui/on-unimplemented/self-types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![feature(rustc_attrs)]

#[rustc_on_unimplemented(
on(Self = "{union}", message = "union self type"),
on(Self = "{enum}", message = "enum self type"),
on(Self = "{struct}", message = "struct self type"),
message = "fallback self type `{Self}`"
)]
trait Trait {}

union Union {
value: u8,
}

enum Enum {
Variant,
}

struct Struct;

fn needs_trait<T: Trait>() {}

fn main() {
needs_trait::<Union>();
//~^ ERROR union self type
needs_trait::<Enum>();
//~^ ERROR enum self type
needs_trait::<Struct>();
//~^ ERROR struct self type
}
69 changes: 69 additions & 0 deletions tests/ui/on-unimplemented/self-types.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
error[E0277]: union self type
--> $DIR/self-types.rs:24:19
|
LL | needs_trait::<Union>();
| ^^^^^ unsatisfied trait bound
|
help: the trait `Trait` is not implemented for `Union`
--> $DIR/self-types.rs:11:1
|
LL | union Union {
| ^^^^^^^^^^^
help: this trait has no implementations, consider adding one
--> $DIR/self-types.rs:9:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
note: required by a bound in `needs_trait`
--> $DIR/self-types.rs:21:19
|
LL | fn needs_trait<T: Trait>() {}
| ^^^^^ required by this bound in `needs_trait`

error[E0277]: enum self type
--> $DIR/self-types.rs:26:19
|
LL | needs_trait::<Enum>();
| ^^^^ unsatisfied trait bound
|
help: the trait `Trait` is not implemented for `Enum`
--> $DIR/self-types.rs:15:1
|
LL | enum Enum {
| ^^^^^^^^^
help: this trait has no implementations, consider adding one
--> $DIR/self-types.rs:9:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
note: required by a bound in `needs_trait`
--> $DIR/self-types.rs:21:19
|
LL | fn needs_trait<T: Trait>() {}
| ^^^^^ required by this bound in `needs_trait`

error[E0277]: struct self type
--> $DIR/self-types.rs:28:19
|
LL | needs_trait::<Struct>();
| ^^^^^^ unsatisfied trait bound
|
help: the trait `Trait` is not implemented for `Struct`
--> $DIR/self-types.rs:19:1
|
LL | struct Struct;
| ^^^^^^^^^^^^^
help: this trait has no implementations, consider adding one
--> $DIR/self-types.rs:9:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
note: required by a bound in `needs_trait`
--> $DIR/self-types.rs:21:19
|
LL | fn needs_trait<T: Trait>() {}
| ^^^^^ required by this bound in `needs_trait`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
Loading
Loading