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
33 changes: 28 additions & 5 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttributeKind::OnUnimplemented { directive } => {
self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())
}
AttributeKind::OnConst { span, .. } => {
self.check_diagnostic_on_const(*span, hir_id, target, item)
AttributeKind::OnConst { span, directive } => {
self.check_diagnostic_on_const(*span, hir_id, target, item, directive.as_deref())
}
AttributeKind::OnMove { directive } => {
self.check_diagnostic_on_move(hir_id, directive.as_deref())
Expand Down Expand Up @@ -545,10 +545,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
hir_id: HirId,
target: Target,
item: Option<ItemLike<'_>>,
directive: Option<&Directive>,
) {
// We only check the non-constness here. A diagnostic for use
// on not-trait impl items is issued during attribute parsing.
if target == (Target::Impl { of_trait: true }) {
if let Some(directive) = directive
&& let Node::Item(Item { kind: ItemKind::Impl(hir::Impl { generics, .. }), .. }) =
self.tcx.hir_node(hir_id)
{
directive.visit_params(&mut |argument_name, span| {
let has_generic = generics.params.iter().any(|p| {
if !matches!(p.kind, GenericParamKind::Lifetime { .. })
&& let ParamName::Plain(name) = p.name
&& name.name == argument_name
{
true
} else {
false
}
});
if !has_generic {
self.tcx.emit_node_span_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
hir_id,
span,
diagnostics::OnConstMalformedFormatLiterals { name: argument_name },
)
}
});
}
match item.unwrap() {
ItemLike::Item(it) => match it.expect_impl().constness {
Constness::Const { .. } => {
Expand All @@ -566,9 +592,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
ItemLike::ForeignItem => {}
}
}
// FIXME(#155570) Can we do something with generic args here?
// regardless, we don't check the validity of generic args here
// ...whose generics would that be, anyway? The traits' or the impls'?
}

/// Checks use of generic formatting parameters in `#[diagnostic::on_move]`
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,13 @@ pub(crate) struct OnMoveMalformedFormatLiterals {
pub name: Symbol,
}

#[derive(Diagnostic)]
#[diag("unknown parameter `{$name}`")]
#[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)]
pub(crate) struct OnConstMalformedFormatLiterals {
pub name: Symbol,
}

#[derive(Diagnostic)]
#[diag("unused target expression is specified for glob or list delegation")]
pub(crate) struct GlobOrListDelegationUnusedTargetExpr {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use rustc_middle::ty::print::{
PrintTraitRefExt as _, with_forced_trimmed_paths,
};
use rustc_middle::ty::{
self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt, Unnormalized, Upcast,
self, GenericArgKind, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitableExt, Unnormalized, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::CrateNum;
Expand Down Expand Up @@ -916,11 +916,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
find_attr!(self.tcx, impl_did, OnConst {directive, ..} => directive.as_deref())
.flatten()
{
let (_, format_args) = self.on_unimplemented_components(
let (_, mut format_args) = self.on_unimplemented_components(
trait_ref,
main_obligation,
diag.long_ty_path(),
false,
);
if let ty::Adt(def, args) = trait_ref.self_ty().skip_binder().kind() {
for param in self.tcx.generics_of(def.did()).own_params.iter() {
match param.kind {
GenericParamDefKind::Type { .. }
| GenericParamDefKind::Const { .. } => {
format_args
.generic_args
.push((param.name, args[param.index as usize].to_string()));
}
_ => continue,
}
}
}
let CustomDiagnostic { message, label, notes, parent_label: _ } =
command.eval(None, &format_args);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return CustomDiagnostic::default();
}
let (filter_options, format_args) =
self.on_unimplemented_components(trait_pred, obligation, long_ty_path);
self.on_unimplemented_components(trait_pred, obligation, long_ty_path, true);
if let Some(command) = find_attr!(self.tcx, trait_pred.def_id(), OnUnimplemented {directive, ..} => directive.as_deref()).flatten() {
command.eval(
Some(&filter_options),
Expand All @@ -62,6 +62,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>,
obligation: &PredicateObligation<'tcx>,
long_ty_path: &mut Option<PathBuf>,
print_infer_ty_var: bool,
) -> (FilterOptions, FormatArgs) {
let (def_id, args) = (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args);
let trait_pred = trait_pred.skip_binder();
Expand Down Expand Up @@ -244,7 +245,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
{
self.tcx.short_string(ty, long_ty_path)
if print_infer_ty_var == false
&& let ty::Infer(ty::TyVar(_)) = ty.kind()
{
format!("{}", param.name)
} else {
self.tcx.short_string(ty, long_ty_path)
}
} else {
trait_pred.trait_ref.args[param.index as usize].to_string()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0277]: the trait bound `X<u8, &str>: const Y<_>` is not satisfied
--> $DIR/generic_parameters_handling.rs:22:6
|
LL | .blah();
| ^^^^
|
= note: Self = X<u8, &str>, Z = Z, A = u8, B = &str

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0277]: the trait bound `X<u8, &str>: const Y<_>` is not satisfied
--> $DIR/generic_parameters_handling.rs:22:6
|
LL | .blah();
| ^^^^
|
= note: Self = X<u8, &str>, Z = Z, A = u8, B = &str

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#![crate_type = "lib"]
#![feature(diagnostic_on_const, const_trait_impl)]

pub struct X<A, B> {
field: (A, B),
}

pub const trait Y<Z> {
fn blah(&self) {}
}

#[diagnostic::on_const(note = "Self = {Self}, Z = {Z}, A = {A}, B = {B}")]
impl<Z, A, B> Y<Z> for X<A, B> {}

const _: () = {
X {
field: (42_u8, "hello"),
}
.blah();
//~^ ERROR the trait bound `X<u8, &str>: const Y<_>` is not satisfied [E0277]
//~| NOTE Self = X<u8, &str>, Z = Z, A = u8, B = &str
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![crate_type = "lib"]
#![feature(diagnostic_on_const)]
#![feature(const_trait_impl)]

pub struct X;

const trait Y {
fn blah(&self) {}
}

#[diagnostic::on_const(
message = "my message {Foo}",
//~^ WARN unknown parameter `Foo`
label = "my label {Bar}",
//~^ WARN unknown parameter `Bar`
note = "my label {Baz}",
//~^ WARN unknown parameter `Baz`
)]
impl Y for X {}

const _: () = {
X {}.blah();
//~^ ERROR my message {Foo} [E0277]

};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
warning: unknown parameter `Foo`
--> $DIR/malformed_format_literals.rs:12:28
|
LL | message = "my message {Foo}",
| ^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

warning: unknown parameter `Bar`
--> $DIR/malformed_format_literals.rs:14:24
|
LL | label = "my label {Bar}",
| ^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

warning: unknown parameter `Baz`
--> $DIR/malformed_format_literals.rs:16:23
|
LL | note = "my label {Baz}",
| ^^^
|
= help: expect either a generic argument name or `{Self}` as format argument

error[E0277]: my message {Foo}
--> $DIR/malformed_format_literals.rs:22:10
|
LL | X {}.blah();
| ^^^^ my label {Bar}
|
= note: my label {Baz}

error: aborting due to 1 previous error; 3 warnings emitted

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