Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ impl OnUnimplementedParser {
let span = cx.attr_span;
self.span = Some(span);

if !matches!(cx.target, Target::Trait) {
cx.emit_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
DiagnosticOnUnimplementedOnlyForTraits,
span,
);
return;
}
// match cx.target {
// Target::Trait => {}
// Target::Fn => {}
// _ => {
// cx.emit_lint(
// MISPLACED_DIAGNOSTIC_ATTRIBUTES,
// DiagnosticOnUnimplementedOnlyForTraits,
// span,
// );
// return;
// }
// }

let Some(items) = parse_list(cx, args, mode) else { return };

Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_hir/src/attrs/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ impl CustomDiagnostic {

self.notes.extend(di.notes.iter().map(|n| n.format(args)))
}

pub fn merge(&mut self, other: Self) {
if other.message.is_some() {
self.message = other.message;
}
if other.label.is_some() {
self.label = other.label;
}
if other.parent_label.is_some() {
self.parent_label = other.parent_label;
}

self.notes.extend(other.notes);
}
}

/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
Expand Down Expand Up @@ -248,6 +262,7 @@ impl Filter {
FlagOrNv::Flag(b) => options.has_flag(*b),
FlagOrNv::NameValue(NameValue { name, value }) => {
let value = value.format(&options.generic_args);
tracing::info!(?value);
options.contains(*name, value)
}
})
Expand Down Expand Up @@ -454,6 +469,7 @@ impl FilterOptions {
}
}
pub fn contains(&self, name: Name, value: String) -> bool {
tracing::info!(?name, ?value);
match name {
Name::SelfUpper => self.self_types.contains(&value),
Name::FromDesugaring => self.from_desugaring.is_some_and(|ds| ds.matches(&value)),
Expand Down
27 changes: 17 additions & 10 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::Deprecated { span: attr_span, .. }) => {
self.check_deprecated(hir_id, *attr_span, target)
}
Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => {
Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, .. }) => {
self.check_target_feature(hir_id, *attr_span, target, attrs)
}
Attribute::Parsed(AttributeKind::RustcDumpObjectLifetimeDefaults) => {
Expand Down Expand Up @@ -182,28 +182,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
&Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => {
self.check_sanitize(attr_span, on_set | off_set, span, target);
},
}
Attribute::Parsed(AttributeKind::Link(_, attr_span)) => {
self.check_link(hir_id, *attr_span, span, target)
},
}
Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
self.check_macro_export(hir_id, *span, target)
},
}
Attribute::Parsed(AttributeKind::RustcLegacyConstGenerics{attr_span, fn_indexes}) => {
self.check_rustc_legacy_const_generics(item, *attr_span, fn_indexes)
},
}
Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target),
Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
self.check_eii_impl(impls, target)
},
}
Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => {
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target)
},
Attribute::Parsed(AttributeKind::OnUnimplemented{directive}) => {self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())},
Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)},
}
Attribute::Parsed(AttributeKind::OnUnimplemented { directive } ) => {
self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())
}
Attribute::Parsed(AttributeKind::OnConst{ span, .. }) => {
self.check_diagnostic_on_const(*span, hir_id, target, item)
}
Attribute::Parsed(AttributeKind::OnMove { directive }) => {
self.check_diagnostic_on_move(hir_id, directive.as_deref())
},
}
Attribute::Parsed(
// tidy-alphabetical-start
AttributeKind::RustcAllowIncoherentImpl(..)
Expand Down Expand Up @@ -521,6 +525,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
)
}
})
} else {
let node = self.tcx.hir_node(hir_id);
tracing::info!(?node);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,37 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
obligation: &PredicateObligation<'tcx>,
long_ty_path: &mut Option<PathBuf>,
) -> CustomDiagnostic {
let mut custom = CustomDiagnostic::default();
if trait_pred.polarity() != ty::PredicatePolarity::Positive {
return CustomDiagnostic::default();
return custom;
}
let (filter_options, format_args) =
self.on_unimplemented_components(trait_pred, obligation, long_ty_path);
if let Some(command) = find_attr!(self.tcx, trait_pred.def_id(), OnUnimplemented {directive, ..} => directive.as_deref()).flatten() {
command.eval(
Some(&filter_options),
&format_args,
if let Some(command) = find_attr!(
self.tcx,
trait_pred.def_id(),
OnUnimplemented { directive, .. } => directive.as_deref()
)
.flatten()
{
custom = command.eval(Some(&filter_options), &format_args)
}
if let ObligationCauseCode::FunctionArg { parent_code, .. } = obligation.cause.code()
&& let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, _) = &**parent_code
&& let Some(command) = find_attr!(
self.tcx,
*def_id,
OnUnimplemented { directive, .. } => directive.as_deref()
)
} else {
CustomDiagnostic::default()
.flatten()
{
tracing::info!("{:#?}", obligation.cause.code());
let x = command.eval(Some(&filter_options), &format_args);
tracing::info!(?x);
custom.merge(x);
}
tracing::info!(?custom);
custom
}

pub(crate) fn on_unimplemented_components(
Expand Down Expand Up @@ -250,6 +268,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.collect();

let format_args = FormatArgs { this, this_sugared, generic_args, item_context };
tracing::info!("{filter_options:#?}");
(filter_options, format_args)
}
}
7 changes: 7 additions & 0 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,13 @@ pub trait Extend<A> {
/// assert_eq!("abcdef", &message);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
message = "can't extend `{Self}` with an iterator of `{A}` items",
on(
all(Self = "alloc::vec::Vec<&str>", A = "alloc::string::String"),
note = "you might have meant to extend a `Vec<String>` or pass in an `Iterator<Item = &str>`"
)
)]
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);

/// Extends a collection with exactly one element.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,6 @@ LL | #[diagnostic::on_unimplemented = "Message"]
|
= help: only `message`, `note` and `label` are allowed as options

warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1
|
LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

error[E0277]: trait has `()` and `i32` as params
--> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15
|
Expand Down Expand Up @@ -212,6 +204,6 @@ note: required by a bound in `takes_baz`
LL | fn takes_baz(_: impl Baz) {}
| ^^^ required by this bound in `takes_baz`

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

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
= help: only `message`, `note` and `label` are allowed as options
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:7:1
|
LL | #[diagnostic::on_unimplemented(message = "Baz")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

warning: malformed `diagnostic::on_unimplemented` attribute
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:11:50
|
Expand Down Expand Up @@ -159,6 +151,6 @@ note: required by a bound in `take_test`
LL | fn take_test(_: impl Test) {}
| ^^^^ required by this bound in `take_test`

error: aborting due to 5 previous errors; 8 warnings emitted
error: aborting due to 5 previous errors; 7 warnings emitted

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
--> $DIR/on_impl_trait.rs:8:1
|
LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

error[E0277]: the trait bound `{integer}: Alias` is not satisfied
error[E0277]: blah
--> $DIR/on_impl_trait.rs:16:9
|
LL | foo(&1);
| --- ^^ the trait `Test` is not implemented for `{integer}`
| --- ^^ blah
| |
| required by a bound introduced by this call
|
= help: the trait `Test` is not implemented for `{integer}`
= note: blah
help: this trait has no implementations, consider adding one
--> $DIR/on_impl_trait.rs:6:1
|
Expand All @@ -26,6 +20,6 @@ note: required by a bound in `foo`
LL | fn foo<T: Alias>(v: &T) {}
| ^^^^^ required by this bound in `foo`

error: aborting due to 1 previous error; 1 warning emitted
error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
23 changes: 23 additions & 0 deletions tests/ui/trait-bounds/vec-extend-unmet-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
fn main() {
let mut x = vec!["a", "b", "c"];
x.extend([String::from("z")]);
//~^ ERROR can't extend `Vec<&str>` with an iterator of `String` items
//~| NOTE the trait `Extend<String>` is not implemented for `Vec<&str>`
//~| NOTE you might have meant to extend a `Vec<String>` or pass in an `Iterator<Item = &str>`
//~| HELP `Vec<T, A>` implements trait `Extend<A>`
x.extend(String::from("z"));
//~^ ERROR `String` is not an iterator
//~| NOTE `String` is not an iterator; try calling `.chars()` or `.bytes()`
//~| NOTE required by a bound introduced by this call
//~| HELP the trait `Iterator` is not implemented for `String`
//~| NOTE required for `String` to implement `IntoIterator`
//~| NOTE required by a bound in `extend`
x.extend(1);
//~^ ERROR `{integer}` is not an iterator
//~| NOTE `{integer}` is not an iterator
//~| NOTE required by a bound introduced by this call
//~| HELP the trait `Iterator` is not implemented for `{integer}`
//~| NOTE required for `{integer}` to implement `IntoIterator`
//~| NOTE required by a bound in `extend`
//~| NOTE if you want to iterate between `start` until a value `end`
}
45 changes: 45 additions & 0 deletions tests/ui/trait-bounds/vec-extend-unmet-bound.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
error[E0277]: can't extend `Vec<&str>` with an iterator of `String` items
--> $DIR/vec-extend-unmet-bound.rs:3:7
|
LL | x.extend([String::from("z")]);
| ^^^^^^ the trait `Extend<String>` is not implemented for `Vec<&str>`
|
= note: you might have meant to extend a `Vec<String>` or pass in an `Iterator<Item = &str>`
help: `Vec<T, A>` implements trait `Extend<A>`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
= note: `Extend<T>`
::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
= note: `Extend<&T>`

error[E0277]: `String` is not an iterator
--> $DIR/vec-extend-unmet-bound.rs:8:14
|
LL | x.extend(String::from("z"));
| ------ ^^^^^^^^^^^^^^^^^ `String` is not an iterator; try calling `.chars()` or `.bytes()`
| |
| required by a bound introduced by this call
|
= help: the trait `Iterator` is not implemented for `String`
= note: required for `String` to implement `IntoIterator`
note: required by a bound in `extend`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL

error[E0277]: `{integer}` is not an iterator
--> $DIR/vec-extend-unmet-bound.rs:15:14
|
LL | x.extend(1);
| ------ ^ `{integer}` is not an iterator
| |
| required by a bound introduced by this call
|
= help: the trait `Iterator` is not implemented for `{integer}`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
= note: required for `{integer}` to implement `IntoIterator`
note: required by a bound in `extend`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL

error: aborting due to 3 previous errors

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