Skip to content
Open
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
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 @@ -271,6 +271,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
54 changes: 49 additions & 5 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use rustc_session::errors::feature_err;
use rustc_session::lint;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
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 @@ -1212,24 +1212,59 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
let mut is_c = false;
let mut is_simd = false;
let mut is_transparent = false;
let mut is_align = false;
let mut is_packed = false;
let mut repeated_repr = false;
let mut maybe_last_int_type = None;

for (repr, _repr_span) in reprs {
match repr {
ReprAttr::ReprRust => {
if is_explicit_rust {

@jdonszelmann jdonszelmann Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems very manual, and I'm not sure I like it. The logic gets quite complex. Is there any way you can figure out to do this in a more structured way that makes sure we can't make any logic errors? Something with iterators maybe?

View changes since the review

repeated_repr = true;
}
is_explicit_rust = true;
}
ReprAttr::ReprC => {
if is_c {
repeated_repr = true;
}
is_c = true;
}
ReprAttr::ReprAlign(..) => {}
ReprAttr::ReprPacked(_) => {}
ReprAttr::ReprAlign(..) => {
if is_align {
repeated_repr = true;
}
is_align = true;
}
ReprAttr::ReprPacked(..) => {
if is_packed {
repeated_repr = true;
}
is_packed = true;
}
ReprAttr::ReprSimd => {
if is_simd {
repeated_repr = true;
}
is_simd = true;
}
ReprAttr::ReprTransparent => {
// No need to check for repeated transparent because that is already checked
// when checking for any other attribute together with transparent.
is_transparent = true;
}
ReprAttr::ReprInt(_) => {
ReprAttr::ReprInt(int_type) => {
if let Some(last_int_type) = maybe_last_int_type
&& last_int_type == int_type
{
// We'll "miss" detecting repeated int reprs if the user specifies
// #[repr(u8, u64, u8)] for example. But that's okay because we've got
// conflicting reprs anyway so it's not worth the effort to do more precise
// tracking.
repeated_repr = true;
}
maybe_last_int_type = Some(int_type);
int_reprs += 1;
}
};
Expand Down Expand Up @@ -1274,10 +1309,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.tcx.emit_node_span_lint(
CONFLICTING_REPR_HINTS,
hir_id,
hint_spans.collect::<Vec<Span>>(),
hint_spans.clone().collect::<Vec<Span>>(),
errors::ReprConflictingLint,
);
}

if repeated_repr {
self.tcx.emit_node_span_lint(
REPEATED_REPRS,
hir_id,
hint_spans.collect::<Vec<Span>>(),
errors::RepeatedRepr,
);
}
}

/// Outputs an error for attributes that can only be applied to macros, such as
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,11 @@ pub(crate) struct TransparentIncompatible {
pub target: String,
}

#[derive(Diagnostic)]
#[diag("representation attribute is specified more than once")]

@jdonszelmann jdonszelmann Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd phrase the error as "#[repr(...)] attribute is specified more than once"

View changes since the review

#[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 representation attribute is specified more than once
#[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: representation 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 representation attribute is specified more than once
#[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: representation 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:37:1
|
Expand Down Expand Up @@ -104,124 +115,124 @@ 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: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: 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"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -316,5 +327,5 @@ note: attribute also specified here
LL | #![no_builtins]
| ^^^^^^^^^^^^^^^

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

6 changes: 3 additions & 3 deletions tests/ui/repr/conflicting-repr-hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ struct G(i32); //~ ERROR type has conflicting packed and align representation hi
#[repr(packed)]
struct H(i32); //~ ERROR type has conflicting packed and align representation hints

#[repr(packed, packed(2))]
#[repr(packed, packed(2))] //~ WARN representation attribute is specified more than once
struct I(i32); //~ ERROR type has conflicting packed representation hints

#[repr(packed(2))]
#[repr(packed(2))] //~ WARN representation attribute is specified more than once
#[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
Loading
Loading