Skip to content

Commit 898bb78

Browse files
Rollup merge of rust-lang#51401 - estebank:warn-repr, r=cramertj
Warn on `repr` without hints Fix rust-lang#51376.
2 parents b1a6db2 + 0e3f19d commit 898bb78

File tree

8 files changed

+398
-202
lines changed

8 files changed

+398
-202
lines changed

src/librustc/lint/builtin.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ declare_lint! {
207207
"potentially-conflicting impls were erroneously allowed"
208208
}
209209

210+
declare_lint! {
211+
pub BAD_REPR,
212+
Warn,
213+
"detects incorrect use of `repr` attribute"
214+
}
215+
210216
declare_lint! {
211217
pub DEPRECATED,
212218
Warn,

src/librustc_lint/builtin.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,79 @@ impl EarlyLintPass for AnonymousParameters {
673673
}
674674
}
675675

676+
/// Checks for incorrect use use of `repr` attributes.
677+
#[derive(Clone)]
678+
pub struct BadRepr;
679+
680+
impl LintPass for BadRepr {
681+
fn get_lints(&self) -> LintArray {
682+
lint_array!()
683+
}
684+
}
685+
686+
impl EarlyLintPass for BadRepr {
687+
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
688+
if attr.name() == "repr" {
689+
let list = attr.meta_item_list();
690+
691+
let repr_str = |lit: &str| { format!("#[repr({})]", lit) };
692+
693+
// Emit warnings with `repr` either has a literal assignment (`#[repr = "C"]`) or
694+
// no hints (``#[repr]`)
695+
let has_hints = list.as_ref().map(|ref list| !list.is_empty()).unwrap_or(false);
696+
if !has_hints {
697+
let mut suggested = false;
698+
let mut warn = if let Some(ref lit) = attr.value_str() {
699+
// avoid warning about empty `repr` on `#[repr = "foo"]`
700+
let mut warn = cx.struct_span_lint(
701+
BAD_REPR,
702+
attr.span,
703+
"`repr` attribute isn't configurable with a literal",
704+
);
705+
match format!("{}", lit).as_ref() {
706+
| "C" | "packed" | "rust" | "transparent"
707+
| "u8" | "u16" | "u32" | "u64" | "u128" | "usize"
708+
| "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => {
709+
// if the literal could have been a valid `repr` arg,
710+
// suggest the correct syntax
711+
warn.span_suggestion(
712+
attr.span,
713+
"give `repr` a hint",
714+
repr_str(&lit.as_str()),
715+
);
716+
suggested = true;
717+
}
718+
_ => { // the literal wasn't a valid `repr` arg
719+
warn.span_label(attr.span, "needs a hint");
720+
}
721+
};
722+
warn
723+
} else {
724+
let mut warn = cx.struct_span_lint(
725+
BAD_REPR,
726+
attr.span,
727+
"`repr` attribute must have a hint",
728+
);
729+
warn.span_label(attr.span, "needs a hint");
730+
warn
731+
};
732+
if !suggested {
733+
warn.help(&format!(
734+
"valid hints include `{}`, `{}`, `{}` and `{}`",
735+
repr_str("C"),
736+
repr_str("packed"),
737+
repr_str("rust"),
738+
repr_str("transparent"),
739+
));
740+
warn.note("for more information, visit \
741+
<https://doc.rust-lang.org/reference/type-layout.html>");
742+
}
743+
warn.emit();
744+
}
745+
}
746+
}
747+
}
748+
676749
/// Checks for use of attributes which have been deprecated.
677750
#[derive(Clone)]
678751
pub struct DeprecatedAttr {

src/librustc_lint/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
107107
UnusedImportBraces,
108108
AnonymousParameters,
109109
UnusedDocComment,
110+
BadRepr,
110111
);
111112

112113
add_early_builtin_with_new!(sess,

src/test/compile-fail/issue-43988.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ fn main() {
3434
#[repr]
3535
let _y = "123";
3636
//~^^ ERROR attribute should not be applied to a statement
37+
//~| WARN `repr` attribute must have a hint
3738

3839

3940
fn foo() {}
@@ -44,5 +45,5 @@ fn main() {
4445

4546
let _z = #[repr] 1;
4647
//~^ ERROR attribute should not be applied to an expression
47-
48+
//~| WARN `repr` attribute must have a hint
4849
}

src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@
5959
#![start = "x4300"] //~ WARN unused attribute
6060
// see issue-43106-gating-of-test.rs for crate-level; but non crate-level is below at "4200"
6161
// see issue-43106-gating-of-bench.rs for crate-level; but non crate-level is below at "4100"
62-
#![repr = "3900"] //~ WARN unused attribute
62+
#![repr = "3900"]
63+
//~^ WARN unused attribute
64+
//~| WARN `repr` attribute isn't configurable with a literal
6365
#![path = "3800"] //~ WARN unused attribute
6466
#![abi = "3700"] //~ WARN unused attribute
6567
#![automatically_derived = "3600"] //~ WARN unused attribute
@@ -309,20 +311,25 @@ mod bench {
309311

310312
#[repr = "3900"]
311313
//~^ WARN unused attribute
314+
//~| WARN `repr` attribute isn't configurable with a literal
312315
mod repr {
313316
mod inner { #![repr="3900"] }
314317
//~^ WARN unused attribute
318+
//~| WARN `repr` attribute isn't configurable with a literal
315319

316320
#[repr = "3900"] fn f() { }
317321
//~^ WARN unused attribute
322+
//~| WARN `repr` attribute isn't configurable with a literal
318323

319324
struct S;
320325

321326
#[repr = "3900"] type T = S;
322327
//~^ WARN unused attribute
328+
//~| WARN `repr` attribute isn't configurable with a literal
323329

324330
#[repr = "3900"] impl S { }
325331
//~^ WARN unused attribute
332+
//~| WARN `repr` attribute isn't configurable with a literal
326333
}
327334

328335
#[path = "3800"]

0 commit comments

Comments
 (0)