diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f6765d604acb3..b7e4a449d1ca2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1213,7 +1213,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_explicit_rust = false; let mut is_c = false; let mut is_simd = false; - let mut is_transparent = false; + let mut transparents = 0; + let mut last_int_repr = None; + let mut int_reprs_different = false; for (repr, repr_span) in reprs { match repr { @@ -1284,7 +1286,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } ReprAttr::ReprTransparent => { - is_transparent = true; + transparents += 1; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { @@ -1295,8 +1297,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - ReprAttr::ReprInt(_) => { + ReprAttr::ReprInt(int_type) => { int_reprs += 1; + if let Some(previous_int) = last_int_repr + && previous_int != int_type + { + int_reprs_different = true; + } + last_int_repr = Some(int_type); if target != Target::Enum { self.dcx().emit_err(errors::AttrApplication::Enum { hint_span: *repr_span, @@ -1336,8 +1344,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = reprs.iter().map(|(_, span)| *span); - // Error on repr(transparent, ). - if is_transparent && reprs.len() > 1 { + // Error if repr(transparent) is combined with any other repr apart from additional + // repr(transparent)s. + if transparents > 0 && reprs.len() != transparents { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::TransparentIncompatible { hint_spans, @@ -1346,7 +1355,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } // Error on `#[repr(transparent)]` in combination with // `#[rustc_pass_indirectly_in_non_rustic_abis]` - if is_transparent + if transparents > 0 && let Some(&pass_indirectly_span) = find_attr!(attrs, RustcPassIndirectlyInNonRusticAbis(span) => span) { @@ -1358,11 +1367,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::ReprConflicting { hint_spans }); + return; } // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) - if (int_reprs > 1) + if (int_reprs > 1 && int_reprs_different) || (is_simd && is_c) - || (int_reprs == 1 + || (int_reprs >= 1 && is_c && item.is_some_and(|item| { if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false } diff --git a/tests/ui/repr/repr-repeated-attrs.rs b/tests/ui/repr/repr-repeated-attrs.rs new file mode 100644 index 0000000000000..691b89e4b0688 --- /dev/null +++ b/tests/ui/repr/repr-repeated-attrs.rs @@ -0,0 +1,59 @@ +// Tests that repeated attributes are allowed. + +#[repr(transparent, transparent)] +#[repr(transparent)] +struct SeveralTransparentReprs(*mut u8); + +#[repr(transparent)] +#[repr(transparent)] +struct MultilineOnly(*mut u8); + +#[repr(Rust, Rust)] +struct SeveralRustReprs(u8); + +#[repr(C, C)] +#[repr(C, C, C)] +struct SeveralC(u8); + +#[repr(u8, u8)] +enum SeveralPrimitiveRerprs { + Variant, +} + +#[repr(C, C, u8)] +#[repr(C, u8, u8)] +enum SeveralCAndPrims { + Variant(u8), +} + +#[repr(Rust, u8, u8)] +//~^ ERROR conflicting representation hints [E0566] +enum RustAndPrimDisallowed { + Variant(u8), +} + +#[repr(u8, u8)] +//~^ ERROR conflicting representation hints [E0566] +//~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +#[repr(u16)] +enum ConflictingPrimReprs { + Variant, +} + +#[repr(C, u8)] +//~^ ERROR conflicting representation hints [E0566] +//~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +enum CWithIntsCausesFCW1 { + A, + B, +} + +#[repr(C, C, u8, u8, u8)] +//~^ ERROR conflicting representation hints [E0566] +//~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +enum CWithIntsCausesFCW2 { + A, + B, +} + +fn main() {} diff --git a/tests/ui/repr/repr-repeated-attrs.stderr b/tests/ui/repr/repr-repeated-attrs.stderr new file mode 100644 index 0000000000000..711c5bbc8f9c8 --- /dev/null +++ b/tests/ui/repr/repr-repeated-attrs.stderr @@ -0,0 +1,76 @@ +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:29:8 + | +LL | #[repr(Rust, u8, u8)] + | ^^^^ ^^ ^^ + +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:35:8 + | +LL | #[repr(u8, u8)] + | ^^ ^^ +... +LL | #[repr(u16)] + | ^^^ + | + = 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 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default + +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:43:8 + | +LL | #[repr(C, u8)] + | ^ ^^ + | + = 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 + +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:51:8 + | +LL | #[repr(C, C, u8, u8, u8)] + | ^ ^ ^^ ^^ ^^ + | + = 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 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0566`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:35:8 + | +LL | #[repr(u8, u8)] + | ^^ ^^ +... +LL | #[repr(u16)] + | ^^^ + | + = 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 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:43:8 + | +LL | #[repr(C, u8)] + | ^ ^^ + | + = 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 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/repr-repeated-attrs.rs:51:8 + | +LL | #[repr(C, C, u8, u8, u8)] + | ^ ^ ^^ ^^ ^^ + | + = 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 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default +