diff --git a/Cargo.lock b/Cargo.lock index 6168a0a174719..a10eccb1ce51e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3569,6 +3569,7 @@ dependencies = [ name = "rustc_attr" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 4f2b9d0ef50d9..7439af7aed3ea 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -698,6 +698,7 @@ impl fmt::Display for AlignFromBytesError { impl Align { pub const ONE: Align = Align { pow2: 0 }; + pub const EIGHT: Align = Align { pow2: 3 }; // LLVM has a maximal supported alignment of 2^29, we inherit that. pub const MAX: Align = Align { pow2: 29 }; @@ -707,19 +708,19 @@ impl Align { } #[inline] - pub fn from_bytes(align: u64) -> Result { + pub const fn from_bytes(align: u64) -> Result { // Treat an alignment of 0 bytes like 1-byte alignment. if align == 0 { return Ok(Align::ONE); } #[cold] - fn not_power_of_2(align: u64) -> AlignFromBytesError { + const fn not_power_of_2(align: u64) -> AlignFromBytesError { AlignFromBytesError::NotPowerOfTwo(align) } #[cold] - fn too_large(align: u64) -> AlignFromBytesError { + const fn too_large(align: u64) -> AlignFromBytesError { AlignFromBytesError::TooLarge(align) } diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml index d33416d200380..3b24452450abe 100644 --- a/compiler/rustc_attr/Cargo.toml +++ b/compiler/rustc_attr/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 814104ec78c49..439f13e763570 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,5 +1,6 @@ //! Parsing and validation of builtin attributes +use rustc_abi::Align; use rustc_ast::{self as ast, attr}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; @@ -919,10 +920,10 @@ pub enum ReprAttr { ReprInt(IntType), ReprRust, ReprC, - ReprPacked(u32), + ReprPacked(Align), ReprSimd, ReprTransparent, - ReprAlign(u32), + ReprAlign(Align), } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -968,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { let hint = match item.name_or_empty() { sym::Rust => Some(ReprRust), sym::C => Some(ReprC), - sym::packed => Some(ReprPacked(1)), + sym::packed => Some(ReprPacked(Align::ONE)), sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), sym::align => { @@ -1209,11 +1210,17 @@ fn allow_unstable<'a>( }) } -pub fn parse_alignment(node: &ast::LitKind) -> Result { +pub fn parse_alignment(node: &ast::LitKind) -> Result { if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first if literal.get().is_power_of_two() { - // rustc_middle::ty::layout::Align restricts align to <= 2^29 - if *literal <= 1 << 29 { Ok(literal.get() as u32) } else { Err("larger than 2^29") } + // 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") } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index f9eaa0d94cbbd..870e5ab329619 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -417,7 +417,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); } if let Some(align) = codegen_fn_attrs.alignment { - llvm::set_alignment(llfn, align as usize); + llvm::set_alignment(llfn, align); } to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 85277db6d538a..68c1770c1d4a1 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -16,6 +16,7 @@ use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Instance; +use rustc_target::abi::Align; use std::cell::RefCell; @@ -23,7 +24,7 @@ pub(crate) mod ffi; pub(crate) mod map_data; pub mod mapgen; -const VAR_ALIGN_BYTES: usize = 8; +const VAR_ALIGN: Align = Align::EIGHT; /// A context object for maintaining all state needed by the coverageinfo module. pub struct CrateCoverageContext<'ll, 'tcx> { @@ -225,7 +226,7 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>( llvm::set_global_constant(llglobal, true); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::set_section(llglobal, &covmap_section_name); - llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + llvm::set_alignment(llglobal, VAR_ALIGN); cx.add_used_global(llglobal); } @@ -255,7 +256,7 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>( llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); llvm::set_visibility(llglobal, llvm::Visibility::Hidden); llvm::set_section(llglobal, covfun_section_name); - llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + llvm::set_alignment(llglobal, VAR_ALIGN); llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); cx.add_used_global(llglobal); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 4f5cc575da6e5..6ab1eea959761 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -11,6 +11,7 @@ pub use self::RealPredicate::*; use libc::c_uint; use rustc_data_structures::small_c_str::SmallCStr; use rustc_llvm::RustString; +use rustc_target::abi::Align; use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::str::FromStr; @@ -229,9 +230,9 @@ pub fn set_visibility(llglobal: &Value, visibility: Visibility) { } } -pub fn set_alignment(llglobal: &Value, bytes: usize) { +pub fn set_alignment(llglobal: &Value, align: Align) { unsafe { - ffi::LLVMSetAlignment(llglobal, bytes as c_uint); + ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint); } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1286a724e9574..a880445a27c1b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -964,7 +964,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { for r in attr::parse_repr_attr(tcx.sess, attr) { if let attr::ReprPacked(pack) = r && let Some(repr_pack) = repr.pack - && pack as u64 != repr_pack.bytes() + && pack != repr_pack { struct_span_code_err!( tcx.dcx(), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 7d6d39a2a8a39..ec9697bbd3558 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,6 +1,7 @@ use crate::mir::mono::Linkage; use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_span::symbol::Symbol; +use rustc_target::abi::Align; use rustc_target::spec::SanitizerSet; #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] @@ -42,7 +43,7 @@ pub struct CodegenFnAttrs { pub instruction_set: Option, /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be /// aligned to. - pub alignment: Option, + pub alignment: Option, } #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 99da981b9d611..ef7626a054f65 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1552,7 +1552,6 @@ impl<'tcx> TyCtxt<'tcx> { attr::ReprRust => ReprFlags::empty(), attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { - let pack = Align::from_bytes(pack as u64).unwrap(); min_pack = Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { @@ -1584,7 +1583,7 @@ impl<'tcx> TyCtxt<'tcx> { ReprFlags::empty() } attr::ReprAlign(align) => { - max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); + max_align = max_align.max(Some(align)); ReprFlags::empty() } }); diff --git a/tests/ui/repr/repr-align.rs b/tests/ui/repr/repr-align.rs index 58ecf9a518327..33aa727d4bd0e 100644 --- a/tests/ui/repr/repr-align.rs +++ b/tests/ui/repr/repr-align.rs @@ -15,6 +15,10 @@ struct S2(i32); #[repr(align(536870912))] // ok: this is the largest accepted alignment struct S3(i32); +#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two +struct S4(i32); + #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer enum E0 { A, B } @@ -30,4 +34,8 @@ enum E2 { A, B } #[repr(align(536870912))] // ok: this is the largest accepted alignment enum E3 { A, B } +#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two +enum E4 { A, B } + fn main() {} diff --git a/tests/ui/repr/repr-align.stderr b/tests/ui/repr/repr-align.stderr index bb0e17ba39558..660247840c48a 100644 --- a/tests/ui/repr/repr-align.stderr +++ b/tests/ui/repr/repr-align.stderr @@ -16,24 +16,36 @@ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 LL | #[repr(align(4294967296))] | ^^^^^^^^^^ -error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer +error[E0589]: invalid `repr(align)` attribute: not a power of two --> $DIR/repr-align.rs:18:14 | +LL | #[repr(align(0))] + | ^ + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:22:14 + | LL | #[repr(align(16.0))] | ^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:22:14 + --> $DIR/repr-align.rs:26:14 | LL | #[repr(align(15))] | ^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:26:14 + --> $DIR/repr-align.rs:30:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:37:14 + | +LL | #[repr(align(0))] + | ^ + error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer --> $DIR/repr-align.rs:3:14 | @@ -58,16 +70,24 @@ LL | #[repr(align(4294967296))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer +error[E0589]: invalid `repr(align)` attribute: not a power of two --> $DIR/repr-align.rs:18:14 | +LL | #[repr(align(0))] + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:22:14 + | LL | #[repr(align(16.0))] | ^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:22:14 + --> $DIR/repr-align.rs:26:14 | LL | #[repr(align(15))] | ^^ @@ -75,13 +95,21 @@ LL | #[repr(align(15))] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:26:14 + --> $DIR/repr-align.rs:30:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 12 previous errors +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:37:14 + | +LL | #[repr(align(0))] + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0589`.