Turn warning into lint

This commit is contained in:
Esteban Küber 2018-06-06 14:11:48 -07:00
parent 2c7099baeb
commit 3580de8c6d
7 changed files with 314 additions and 277 deletions

View File

@ -14,7 +14,7 @@
//! conflicts between multiple such attributes attached to the same
//! item.
use syntax_pos::{BytePos, Span};
use syntax_pos::Span;
use ty::TyCtxt;
use hir;
@ -154,59 +154,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
let hints: Vec<_> = item.attrs
.iter()
.filter(|attr| attr.name() == "repr")
.filter_map(|attr| {
let list = attr.meta_item_list();
// Emit warnings with `repr` either has a literal assignment (`#[repr = "C"]`) or
// no hints (``#[repr]`)
let has_hints = list.as_ref().map(|ref list| !list.is_empty()).unwrap_or(false);
if !has_hints {
let mut suggested = false;
let mut warn = if let Some(ref lit) = attr.value_str() {
// avoid warning about empty `repr` on `#[repr = "foo"]`
let sp = match format!("{}", lit).as_ref() {
"C" | "packed" | "rust" | "u*" | "i*" => {
let lo = attr.span.lo() + BytePos(2);
let hi = attr.span.hi() - BytePos(1);
suggested = true;
attr.span.with_lo(lo).with_hi(hi)
}
_ => attr.span, // the literal wasn't a valid `repr` arg
};
let mut warn = self.tcx.sess.struct_span_warn(
sp,
"`repr` attribute isn't configurable with a literal",
);
if suggested {
// if the literal could have been a valid `repr` arg,
// suggest the correct syntax
warn.span_suggestion(
sp,
"give `repr` a hint",
format!("repr({})", lit),
);
} else {
warn.span_label(attr.span, "needs a hint");
}
warn
} else {
let mut warn = self.tcx.sess.struct_span_warn(
attr.span,
"`repr` attribute must have a hint",
);
warn.span_label(attr.span, "needs a hint");
warn
};
if !suggested {
warn.help("valid hints include `#[repr(C)]`, `#[repr(packed)]` and \
`#[repr(rust)]`");
warn.note("for more information, visit \
<https://doc.rust-lang.org/nomicon/other-reprs.html>");
}
warn.emit();
}
list
})
.filter_map(|attr| attr.meta_item_list())
.flat_map(|hints| hints)
.collect();

View File

@ -206,6 +206,12 @@ declare_lint! {
"potentially-conflicting impls were erroneously allowed"
}
declare_lint! {
pub BAD_REPR,
Warn,
"detects incorrect use of `repr` attribute"
}
declare_lint! {
pub DEPRECATED,
Warn,

View File

@ -673,6 +673,75 @@ impl EarlyLintPass for AnonymousParameters {
}
}
/// Checks for incorrect use use of `repr` attributes.
#[derive(Clone)]
pub struct BadRepr;
impl LintPass for BadRepr {
fn get_lints(&self) -> LintArray {
lint_array!()
}
}
impl EarlyLintPass for BadRepr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
if attr.name() == "repr" {
let list = attr.meta_item_list();
// Emit warnings with `repr` either has a literal assignment (`#[repr = "C"]`) or
// no hints (``#[repr]`)
let has_hints = list.as_ref().map(|ref list| !list.is_empty()).unwrap_or(false);
if !has_hints {
let mut suggested = false;
let mut warn = if let Some(ref lit) = attr.value_str() {
// avoid warning about empty `repr` on `#[repr = "foo"]`
let sp = match format!("{}", lit).as_ref() {
"C" | "packed" | "rust" | "u*" | "i*" => {
let lo = attr.span.lo() + BytePos(2);
let hi = attr.span.hi() - BytePos(1);
suggested = true;
attr.span.with_lo(lo).with_hi(hi)
}
_ => attr.span, // the literal wasn't a valid `repr` arg
};
let mut warn = cx.struct_span_lint(
BAD_REPR,
sp,
"`repr` attribute isn't configurable with a literal",
);
if suggested {
// if the literal could have been a valid `repr` arg,
// suggest the correct syntax
warn.span_suggestion(
sp,
"give `repr` a hint",
format!("repr({})", lit),
);
} else {
warn.span_label(attr.span, "needs a hint");
}
warn
} else {
let mut warn = cx.struct_span_lint(
BAD_REPR,
attr.span,
"`repr` attribute must have a hint",
);
warn.span_label(attr.span, "needs a hint");
warn
};
if !suggested {
warn.help("valid hints include `#[repr(C)]`, `#[repr(packed)]` and \
`#[repr(rust)]`");
warn.note("for more information, visit \
<https://doc.rust-lang.org/nomicon/other-reprs.html>");
}
warn.emit();
}
}
}
}
/// Checks for use of attributes which have been deprecated.
#[derive(Clone)]
pub struct DeprecatedAttr {

View File

@ -107,6 +107,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedImportBraces,
AnonymousParameters,
UnusedDocComment,
BadRepr,
);
add_early_builtin_with_new!(sess,

View File

@ -59,7 +59,9 @@
#![start = "x4300"] //~ WARN unused attribute
// see issue-43106-gating-of-test.rs for crate-level; but non crate-level is below at "4200"
// see issue-43106-gating-of-bench.rs for crate-level; but non crate-level is below at "4100"
#![repr = "3900"] //~ WARN unused attribute
#![repr = "3900"]
//~^ WARN unused attribute
//~| WARN `repr` attribute isn't configurable with a literal
#![path = "3800"] //~ WARN unused attribute
#![abi = "3700"] //~ WARN unused attribute
#![automatically_derived = "3600"] //~ WARN unused attribute

View File

@ -4,6 +4,7 @@ warning: `repr` attribute must have a hint
LL | #[repr]
| ^^^^^^^ needs a hint
|
= note: #[warn(bad_repr)] on by default
= help: valid hints include `#[repr(C)]`, `#[repr(packed)]` and `#[repr(rust)]`
= note: for more information, visit <https://doc.rust-lang.org/nomicon/other-reprs.html>