Skip to content
16 changes: 14 additions & 2 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,19 @@ impl OptimizeAttr {
}
}

#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, StableHash, PrintAttribute)]
#[derive(
PartialEq,
Eq,
Debug,
PartialOrd,
Ord,
Encodable,
Decodable,
Copy,
Clone,
StableHash,
PrintAttribute
)]
pub enum ReprAttr {
ReprInt(IntType),
ReprRust,
Expand All @@ -187,7 +199,7 @@ pub enum TransparencyError {
MultipleTransparencyAttrs(Span, Span),
}

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
#[derive(Eq, PartialEq, Debug, Copy, Clone, PartialOrd, Ord)]
#[derive(Encodable, Decodable, StableHash, PrintAttribute)]
pub enum IntType {
SignedInt(ast::IntTy),
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,30 @@ declare_lint! {
};
}

declare_lint! {
/// The `repeated_reprs` lint detects when the same representation is
/// specified more than once in a `#[repr(..)]` attribute.
///
/// ### Example
///
/// ```rust
/// #[repr(C)]
/// #[repr(C)]
/// enum Foo { A }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// While some representations may be specified more than once, the compiler
/// will reject repeated uses of some others. For consistency, prefer to
/// only specify the representation once.
pub REPEATED_REPRS,
Warn,
"detects repeated representations in `#[repr(..)]` attributes",
}

declare_lint! {
/// The `meta_variable_misuse` lint detects possible meta-variable misuse
/// in macro definitions.
Expand Down
38 changes: 34 additions & 4 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ use rustc_session::errors::feature_err;
use rustc_session::lint;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, REPEATED_REPRS,
UNUSED_ATTRIBUTES,
};
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
Expand Down Expand Up @@ -1236,20 +1237,49 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
ReprAttr::ReprC => {
is_c = true;
}
ReprAttr::ReprAlign(..) => {}
ReprAttr::ReprPacked(_) => {}
ReprAttr::ReprAlign(..) => (),
ReprAttr::ReprPacked(..) => (),
ReprAttr::ReprSimd => {
is_simd = true;
}
ReprAttr::ReprTransparent => {
is_transparent = true;
}
ReprAttr::ReprInt(_) => {
ReprAttr::ReprInt(..) => {
int_reprs += 1;
}
};
}

if !reprs.is_empty() {
let sorted_reprs = {
let mut to_sort = reprs.to_owned();
to_sort.sort();
to_sort
};

// To collect all duplicates, get subslices where all of the elements of the subslice
// are equal, then filter out all those whose length is not 1. We could return warnings
// for each of them, but that's annoyingly excessive. So we instead collect all spans in
// one big Vec.
let spans: Vec<Span> = sorted_reprs
.chunk_by(|(a, _), (b, _)| a == b)
.map(ToOwned::to_owned)
.filter(|slice| slice.len() != 1)
.flatten()
.map(|(_, span)| span)
.collect();

if !spans.is_empty() {
self.tcx.emit_node_span_lint(
REPEATED_REPRS,
hir_id,
spans,
diagnostics::RepeatedRepr,
);
}
}

// Just point at all repr hints if there are any incompatibilities.
// This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
let hint_spans = reprs.iter().map(|(_, span)| *span);
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,11 @@ pub(crate) struct TransparentIncompatible {
pub target: String,
}

#[derive(Diagnostic)]
#[diag("`#[repr(..)]` attribute is specified more than once")]
#[note("for consistency, only specify the representation once")]
pub(crate) struct RepeatedRepr;

#[derive(Diagnostic)]
#[diag("deprecated attribute must be paired with either stable or unstable attribute", code = E0549)]
pub(crate) struct DeprecatedAttribute {
Expand Down
1 change: 1 addition & 0 deletions tests/ui/attributes/issue-100631.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// can reasonably deal with multiple attributes.
// `repr` will use `TyCtxt::get_attrs` since it's `DuplicatesOk`.
#[repr(C)] //~ ERROR: unsupported representation for zero-variant enum [E0084]
//~^ WARN `#[repr(..)]` attribute is specified more than once [repeated_reprs]
#[repr(C)]
enum Foo {}

Expand Down
16 changes: 14 additions & 2 deletions tests/ui/attributes/issue-100631.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
error[E0084]: unsupported representation for zero-variant enum
warning: `#[repr(..)]` attribute is specified more than once
--> $DIR/issue-100631.rs:4:8
|
LL | #[repr(C)]
| ^
LL |
LL | #[repr(C)]
| ^
|
= note: for consistency, only specify the representation once
= note: `#[warn(repeated_reprs)]` on by default

error[E0084]: unsupported representation for zero-variant enum
--> $DIR/issue-100631.rs:4:8
|
LL | #[repr(C)]
| ^
...
LL | enum Foo {}
| -------- zero-variant enum

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

For more information about this error, try `rustc --explain E0084`.
3 changes: 1 addition & 2 deletions tests/ui/lint/unused/unused-attr-duplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ fn t1() {}
#[must_use = "some message"]
//~^ ERROR unused attribute
//~| WARN this was previously accepted
// No warnings for #[repr], would require more logic.
#[repr(C)]
#[repr(C)] //~ WARN `#[repr(..)]` attribute is specified more than once [repeated_reprs]
#[repr(C)]
#[non_exhaustive]
#[non_exhaustive] //~ ERROR unused attribute
Expand Down
53 changes: 32 additions & 21 deletions tests/ui/lint/unused/unused-attr-duplicate.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ note: the lint level is defined here
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^

warning: `#[repr(..)]` attribute is specified more than once
--> $DIR/unused-attr-duplicate.rs:67:8
|
LL | #[repr(C)]
| ^
LL | #[repr(C)]
| ^
|
= note: for consistency, only specify the representation once
= note: `#[warn(repeated_reprs)]` on by default

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:14:1
|
Expand Down Expand Up @@ -193,128 +204,128 @@ LL | #[must_use]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:71:1
--> $DIR/unused-attr-duplicate.rs:70:1
|
LL | #[non_exhaustive]
| ^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:70:1
--> $DIR/unused-attr-duplicate.rs:69:1
|
LL | #[non_exhaustive]
| ^^^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:77:1
--> $DIR/unused-attr-duplicate.rs:76:1
|
LL | #[automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:76:1
--> $DIR/unused-attr-duplicate.rs:75:1
|
LL | #[automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:81:1
--> $DIR/unused-attr-duplicate.rs:80:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:80:1
--> $DIR/unused-attr-duplicate.rs:79:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:84:1
--> $DIR/unused-attr-duplicate.rs:83:1
|
LL | #[cold]
| ^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:83:1
--> $DIR/unused-attr-duplicate.rs:82:1
|
LL | #[cold]
| ^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:86:1
--> $DIR/unused-attr-duplicate.rs:85:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:85:1
--> $DIR/unused-attr-duplicate.rs:84:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:100:1
--> $DIR/unused-attr-duplicate.rs:99:1
|
LL | #[export_name = "exported_symbol_name2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:99:1
--> $DIR/unused-attr-duplicate.rs:98:1
|
LL | #[export_name = "exported_symbol_name"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:105:1
--> $DIR/unused-attr-duplicate.rs:104:1
|
LL | #[no_mangle]
| ^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:104:1
--> $DIR/unused-attr-duplicate.rs:103:1
|
LL | #[no_mangle]
| ^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:109:1
--> $DIR/unused-attr-duplicate.rs:108:1
|
LL | #[used]
| ^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:108:1
--> $DIR/unused-attr-duplicate.rs:107:1
|
LL | #[used]
| ^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:113:1
--> $DIR/unused-attr-duplicate.rs:112:1
|
LL | #[link_section = "__DATA,__mod_init_func"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:112:1
--> $DIR/unused-attr-duplicate.rs:111:1
|
LL | #[link_section = "__TEXT,__text"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:94:5
--> $DIR/unused-attr-duplicate.rs:93:5
|
LL | #[link_name = "rust_dbg_extern_identity_u32"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:93:5
--> $DIR/unused-attr-duplicate.rs:92:5
|
LL | #[link_name = "this_does_not_exist"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

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

2 changes: 1 addition & 1 deletion tests/ui/repr/conflicting-repr-hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct I(i32); //~ ERROR type has conflicting packed representation hints
#[repr(packed)]
struct J(i32); //~ ERROR type has conflicting packed representation hints

#[repr(packed, packed(1))]
#[repr(packed, packed(1))] //~ WARN attribute is specified more than once
struct K(i32);

#[repr(packed, align(8))]
Expand Down
11 changes: 10 additions & 1 deletion tests/ui/repr/conflicting-repr-hints.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ LL | #[repr(u32, u64)]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>

warning: `#[repr(..)]` attribute is specified more than once
--> $DIR/conflicting-repr-hints.rs:46:8
|
LL | #[repr(packed, packed(1))]
| ^^^^^^ ^^^^^^^^^
|
= note: for consistency, only specify the representation once
= note: `#[warn(repeated_reprs)]` on by default

error[E0587]: type has conflicting packed and align representation hints
--> $DIR/conflicting-repr-hints.rs:29:1
|
Expand Down Expand Up @@ -77,7 +86,7 @@ error[E0587]: type has conflicting packed and align representation hints
LL | pub union U {
| ^^^^^^^^^^^

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

Some errors have detailed explanations: E0566, E0587, E0634.
For more information about an error, try `rustc --explain E0566`.
Expand Down
Loading
Loading