diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index f0fc2a5b5e939..f8ccc8594e333 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,4 +1,4 @@ -use rustc_abi::Align; +use rustc_abi::{Align, Size}; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_hir::attrs::{IntType, ReprAttr}; @@ -229,7 +229,7 @@ fn parse_repr_align( return None; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => Some(match align_kind { AlignKind::Packed => ReprAttr::ReprPacked(literal), AlignKind::Align => ReprAttr::ReprAlign(literal), @@ -248,23 +248,35 @@ fn parse_repr_align( } } -fn parse_alignment(node: &LitKind) -> Result { - if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { - // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first - if literal.get().is_power_of_two() { - // Only possible error is larger than 2^29 - literal - .get() - .try_into() - .ok() - .and_then(|v| Align::from_bytes(v).ok()) - .ok_or("larger than 2^29") - } else { - Err("not a power of two") - } - } else { - Err("not an unsuffixed integer") +fn parse_alignment( + node: &LitKind, + cx: &AcceptContext<'_, '_, S>, +) -> Result { + let LitKind::Int(literal, LitIntType::Unsuffixed) = node else { + return Err("not an unsuffixed integer".to_string()); + }; + + // `Align::from_bytes` accepts 0 as a valid input, + // so we check if its a power of two first + if !literal.get().is_power_of_two() { + return Err("not a power of two".to_string()); + } + // lit must be < 2^29 + let align = literal + .get() + .try_into() + .ok() + .and_then(|a| Align::from_bytes(a).ok()) + .ok_or("larger than 2^29".to_string())?; + + // alignment must not be larger than the pointer width (`isize::MAX`) + let max = Size::from_bits(cx.sess.target.pointer_width).signed_int_max() as u64; + if align.bytes() > max { + return Err(format!( + "alignment larger than `isize::MAX` bytes ({max} for the current target)" + )); } + Ok(align) } /// Parse #[align(N)]. @@ -294,7 +306,7 @@ impl RustcAlignParser { return; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), Err(message) => { cx.emit_err(session_diagnostics::InvalidAlignmentValue { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 987c0cb04c84d..7c2044ec235a7 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -227,12 +227,12 @@ pub(crate) struct InvalidReprAlignNeedArg { #[derive(Diagnostic)] #[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)] -pub(crate) struct InvalidReprGeneric<'a> { +pub(crate) struct InvalidReprGeneric { #[primary_span] pub span: Span, pub repr_arg: String, - pub error_part: &'a str, + pub error_part: String, } #[derive(Diagnostic)] @@ -479,7 +479,7 @@ pub(crate) struct InvalidTarget { pub(crate) struct InvalidAlignmentValue { #[primary_span] pub span: Span, - pub error_part: &'static str, + pub error_part: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dacb02afe1612..648163bd1d148 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use std::slice; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::ExternAbi; use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; @@ -190,8 +190,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - Attribute::Parsed(AttributeKind::RustcAlign { align, span: attr_span }) => { - self.check_align(*align, *attr_span) + Attribute::Parsed(AttributeKind::RustcAlign {..}) => { + } Attribute::Parsed(AttributeKind::Naked(..)) => { self.check_naked(hir_id, target) @@ -1335,31 +1335,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - ReprAttr::ReprAlign(align) => { - match target { - Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlign { - span: *repr_span, - item: target.plural_name(), - }); - } - Target::Static if self.tcx.features().static_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { - span: *repr_span, - item: target.plural_name(), - }); - } - _ => { - self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, - span, - }); - } + ReprAttr::ReprAlign(..) => match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: *repr_span, + item: target.plural_name(), + }); } - - self.check_align(*align, *repr_span); - } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: *repr_span, + span, + }); + } + }, ReprAttr::ReprPacked(_) => { if target != Target::Struct && target != Target::Union { self.dcx().emit_err(errors::AttrApplication::StructUnion { @@ -1475,25 +1471,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align(&self, align: Align, span: Span) { - if align.bytes() > 2_u64.pow(29) { - // for values greater than 2^29, a different error will be emitted, make sure that happens - self.dcx().span_delayed_bug( - span, - "alignment greater than 2^29 should be errored on elsewhere", - ); - } else { - // only do this check when <= 2^29 to prevent duplicate errors: - // alignment greater than 2^29 not supported - // alignment is too large for the current target - - let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; - if align.bytes() > max { - self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max }); - } - } - } - /// Outputs an error for attributes that can only be applied to macros, such as /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`. /// (Allows proc_macro functions) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 0cf0d1a5c80ff..b0783d3fe1cca 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -236,15 +236,6 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } -#[derive(Diagnostic)] -#[diag("alignment must not be greater than `isize::MAX` bytes", code = E0589)] -#[note("`isize::MAX` is {$size} for the current target")] -pub(crate) struct InvalidReprAlignForTarget { - #[primary_span] - pub span: Span, - pub size: u64, -} - #[derive(Diagnostic)] #[diag("conflicting representation hints", code = E0566)] pub(crate) struct ReprConflictingLint; diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr index a7b06acb6752b..4fcd33d50d749 100644 --- a/tests/ui/repr/repr_align_greater_usize.msp430.stderr +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -1,18 +1,14 @@ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:23:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:23:14 | LL | #[repr(align(32768))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:26:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:26:14 | LL | #[repr(align(65536))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs index 52a4d23b1eca2..7df1fbe762661 100644 --- a/tests/ui/repr/repr_align_greater_usize.rs +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -20,8 +20,8 @@ use minicore::*; #[repr(align(16384))] struct Kitten; -#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(32768))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct Cat; -#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(65536))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct BigCat;