Skip to content
Merged
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
50 changes: 31 additions & 19 deletions compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -229,7 +229,7 @@ fn parse_repr_align<S: Stage>(
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),
Expand All @@ -248,23 +248,35 @@ fn parse_repr_align<S: Stage>(
}
}

fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
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<S: Stage>(
node: &LitKind,
cx: &AcceptContext<'_, '_, S>,
) -> Result<Align, String> {
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)].
Expand Down Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down
69 changes: 23 additions & 46 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,6 @@ pub(crate) struct ReprConflicting {
pub hint_spans: Vec<Span>,
}

#[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;
Expand Down
16 changes: 6 additions & 10 deletions tests/ui/repr/repr_align_greater_usize.msp430.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/repr/repr_align_greater_usize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading