diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f8ef423a9b0..e5e70ba2033 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -622,6 +622,10 @@ passes_remove_fields = passes_repr_align_function = `repr(align)` attributes on functions are unstable +passes_repr_align_greater_than_target_max = + alignment must not be greater than `isize::MAX` bytes + .note = `isize::MAX` is {$size} for the current target + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index acde27c6728..8c4592cbb36 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -34,6 +34,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -1785,7 +1786,7 @@ fn check_repr( | Target::Union | Target::Enum | Target::Fn - | Target::Method(_) => continue, + | Target::Method(_) => {} _ => { self.dcx().emit_err( errors::AttrApplication::StructEnumFunctionMethodUnion { @@ -1795,6 +1796,8 @@ fn check_repr( ); } } + + self.check_align_value(hint); } sym::packed => { if target != Target::Struct && target != Target::Union { @@ -1892,6 +1895,45 @@ fn check_repr( } } + fn check_align_value(&self, item: &MetaItemInner) { + match item.singleton_lit_list() { + Some(( + _, + MetaItemLit { + kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), .. + }, + )) => { + let val = literal.get() as u64; + if val > 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( + item.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 val > max { + self.dcx().emit_err(errors::InvalidReprAlignForTarget { + span: item.span(), + size: max, + }); + } + } + } + + // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None + // but an error will have already been emitted, so this code should just skip such attributes + Some((_, _)) | None => { + self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))"); + } + } + } + fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b5f1eac1cba..8bd767c1243 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -567,6 +567,15 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } +#[derive(Diagnostic)] +#[diag(passes_repr_align_greater_than_target_max, code = E0589)] +#[note] +pub(crate) struct InvalidReprAlignForTarget { + #[primary_span] + pub span: Span, + pub size: u64, +} + #[derive(LintDiagnostic)] #[diag(passes_repr_conflicting, 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 new file mode 100644 index 00000000000..7c85249c009 --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -0,0 +1,19 @@ +error[E0589]: alignment must not be greater than `isize::MAX` bytes + --> $DIR/repr_align_greater_usize.rs:21:8 + | +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:24:8 + | +LL | #[repr(align(65536))] + | ^^^^^^^^^^^^ + | + = note: `isize::MAX` is 32767 for the current target + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs new file mode 100644 index 00000000000..b47320b6d9b --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -0,0 +1,25 @@ +//@ revisions: msp430 aarch32 +//@[msp430] needs-llvm-components: msp430 +//@[msp430] compile-flags: --target=msp430-none-elf +//@[aarch32] build-pass +//@[aarch32] needs-llvm-components: arm +//@[aarch32] compile-flags: --target=thumbv7m-none-eabi + +// We should fail to compute alignment for types aligned higher than usize::MAX. +// We can't handle alignments that require all 32 bits, so this only affects 16-bit. + +#![feature(lang_items, no_core)] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +#[repr(align(16384))] +struct Kitten; + +#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct Cat; + +#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct BigCat;