migrate the rest of check_attr.rs to translateable diagnostics

This commit is contained in:
Nathan Stocks 2022-10-02 14:34:10 -06:00
parent a7aa1850b2
commit 3fe8e004e9
3 changed files with 110 additions and 62 deletions

View File

@ -564,3 +564,39 @@ passes_useless_assignment =
[true] field
*[false] variable
} of type `{$ty}` to itself
passes_only_has_effect_on =
`#[{$attr_name}]` only has an effect on {$target_name ->
[function] functions
[module] modules
[implementation_block] implementation blocks
*[unspecified] (unspecified--this is a compiler bug)
}
passes_object_lifetime_err =
{$repr}
passes_unrecognized_repr_hint =
unrecognized representation hint
.help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
passes_attribute_should_be_applied_to =
attribute should be applied to {$what ->
[enum] an enum
[struct] a struct
[struct-union] a struct or union
[struct-enum-union] a struct, enum, or union
[struct-enum-function-union] a struct, enum, function, or union
*[unspecified] (unspecified--this is a compiler bug)
}
.label = not {$what ->
[enum] an enum
[struct] a struct
[struct-union] a struct or union
[struct-enum-union] a struct, enum, or union
[struct-enum-function-union] a struct, enum, function, or union
*[unspecified] (unspecified--this is a compiler bug)
}
passes_transparent_incompatible =
transparent {$target} cannot have other repr hints

View File

@ -4,10 +4,13 @@
//! conflicts between multiple such attributes attached to the same
//! item.
use crate::errors::{self, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel};
use crate::errors::{
self, AttributeShouldBeAppliedTo, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel,
ObjectLifetimeErr, OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
};
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
use rustc_errors::{fluent, Applicability, MultiSpan};
use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
@ -164,17 +167,17 @@ fn check_attributes(
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic | sym::proc_macro_derive => {
self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
self.check_generic_attr(hir_id, attr, target, Target::Fn)
}
sym::automatically_derived => {
self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
self.check_generic_attr(hir_id, attr, target, Target::Impl)
}
sym::no_implicit_prelude => {
self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
self.check_generic_attr(hir_id, attr, target, Target::Mod)
}
sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
_ => {}
@ -351,31 +354,17 @@ fn check_generic_attr(
hir_id: HirId,
attr: &Attribute,
target: Target,
allowed_targets: &[Target],
allowed_target: Target,
) {
if !allowed_targets.iter().any(|t| t == &target) {
let name = attr.name_or_empty();
let mut i = allowed_targets.iter();
// Pluralize
let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
b.push_str(", and ");
} else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
b.push_str(" and ");
} else {
b.push_str(", ");
}
// Pluralize
b.push_str(&(allowed_target.to_string() + "s"));
b
});
self.tcx.struct_span_lint_hir(
if target != allowed_target {
self.tcx.emit_spanned_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
&format!("`#[{name}]` only has an effect on {}", supported_names),
|lint| lint,
OnlyHasEffectOn {
attr_name: attr.name_or_empty(),
target_name: allowed_target.name().replace(" ", "_"),
},
);
}
}
@ -432,7 +421,7 @@ fn check_object_lifetime_default(&self, hir_id: HirId) {
ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
};
tcx.sess.span_err(p.span, &repr);
tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
}
}
}
@ -1605,12 +1594,12 @@ fn check_repr(
continue;
}
let (article, allowed_targets) = match hint.name_or_empty() {
let what = match hint.name_or_empty() {
sym::C => {
is_c = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
_ => ("a", "struct, enum, or union"),
_ => "struct-enum-union",
}
}
sym::align => {
@ -1626,12 +1615,12 @@ fn check_repr(
match target {
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
_ => ("a", "struct, enum, function, or union"),
_ => "struct-enum-function-union",
}
}
sym::packed => {
if target != Target::Struct && target != Target::Union {
("a", "struct or union")
"struct-union"
} else {
continue;
}
@ -1639,7 +1628,7 @@ fn check_repr(
sym::simd => {
is_simd = true;
if target != Target::Struct {
("a", "struct")
"struct"
} else {
continue;
}
@ -1648,7 +1637,7 @@ fn check_repr(
is_transparent = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
_ => ("a", "struct, enum, or union"),
_ => "struct-enum-union",
}
}
sym::i8
@ -1665,35 +1654,22 @@ fn check_repr(
| sym::usize => {
int_reprs += 1;
if target != Target::Enum {
("an", "enum")
"enum"
} else {
continue;
}
}
_ => {
struct_span_err!(
self.tcx.sess,
hint.span(),
E0552,
"unrecognized representation hint"
)
.help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, \
`i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
.emit();
self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
continue;
}
};
struct_span_err!(
self.tcx.sess,
hint.span(),
E0517,
"{}",
&format!("attribute should be applied to {article} {allowed_targets}")
)
.span_label(span, &format!("not {article} {allowed_targets}"))
.emit();
self.tcx.sess.emit_err(AttributeShouldBeAppliedTo {
hint_span: hint.span(),
span,
what,
});
}
// Just point at all repr hints if there are any incompatibilities.
@ -1703,14 +1679,9 @@ fn check_repr(
// Error on repr(transparent, <anything else>).
if is_transparent && hints.len() > 1 {
let hint_spans: Vec<_> = hint_spans.clone().collect();
struct_span_err!(
self.tcx.sess,
hint_spans,
E0692,
"transparent {} cannot have other repr hints",
target
)
.emit();
self.tcx
.sess
.emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
}
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
if (int_reprs > 1)

View File

@ -1272,3 +1272,44 @@ pub struct UselessAssignment<'a> {
pub is_field_assign: bool,
pub ty: Ty<'a>,
}
#[derive(LintDiagnostic)]
#[diag(passes::only_has_effect_on)]
pub struct OnlyHasEffectOn {
pub attr_name: Symbol,
pub target_name: String,
}
#[derive(Diagnostic)]
#[diag(passes::object_lifetime_err)]
pub struct ObjectLifetimeErr {
#[primary_span]
pub span: Span,
pub repr: String,
}
#[derive(Diagnostic)]
#[diag(passes::unrecognized_repr_hint, code = "E0552")]
#[help]
pub struct UnrecognizedReprHint {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::attribute_should_be_applied_to, code = "E0517")]
pub struct AttributeShouldBeAppliedTo<'a> {
#[primary_span]
pub hint_span: Span,
#[label]
pub span: Span,
pub what: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::transparent_incompatible, code = "E0692")]
pub struct TransparentIncompatible {
#[primary_span]
pub hint_spans: Vec<Span>,
pub target: String,
}