Rollup merge of #146178 - folkertdev:static-align, r=jdonszelmann,ralfjung,traviscross
Implement `#[rustc_align_static(N)]` on `static`s Tracking issue: https://github.com/rust-lang/rust/issues/146177 ```rust #![feature(static_align)] #[rustc_align_static(64)] static SO_ALIGNED: u64 = 0; ``` We need a different attribute than `rustc_align` because unstable attributes are tied to their feature (we can't have two unstable features use the same unstable attribute). Otherwise this uses all of the same infrastructure as `#[rustc_align]`. r? `@traviscross`
This commit is contained in:
commit
422c76adae
21 changed files with 246 additions and 5 deletions
|
|
@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
|
|||
sym::rustc_std_internal_symbol,
|
||||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
sym::rustc_align,
|
||||
sym::rustc_align_static,
|
||||
// obviously compatible with self
|
||||
sym::naked,
|
||||
// documentation
|
||||
|
|
|
|||
|
|
@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
|||
Some(AttributeKind::Align { align, span })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AlignStaticParser(AlignParser);
|
||||
|
||||
impl AlignStaticParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||
|
||||
fn parse<'c, S: Stage>(
|
||||
&mut self,
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) {
|
||||
self.0.parse(cx, args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for AlignStaticParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
let (align, span) = self.0.0?;
|
||||
Some(AttributeKind::Align { align, span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{
|
|||
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
|
||||
};
|
||||
use crate::attributes::prototype::CustomMirParser;
|
||||
use crate::attributes::repr::{AlignParser, ReprParser};
|
||||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
|
||||
RustcObjectLifetimeDefaultParser,
|
||||
|
|
@ -152,6 +152,7 @@ attribute_parsers!(
|
|||
pub(crate) static ATTRIBUTE_PARSERS = [
|
||||
// tidy-alphabetical-start
|
||||
AlignParser,
|
||||
AlignStaticParser,
|
||||
BodyStabilityParser,
|
||||
ConfusablesParser,
|
||||
ConstStabilityParser,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
|||
if global.to_rvalue().get_type() != val_llty {
|
||||
global.to_rvalue().set_type(val_llty);
|
||||
}
|
||||
|
||||
// NOTE: Alignment from attributes has already been applied to the allocation.
|
||||
set_global_alignment(self, global, alloc.align);
|
||||
|
||||
global.global_set_initializer_rvalue(value);
|
||||
|
|
|
|||
|
|
@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
self.statics_to_rauw.borrow_mut().push((g, new_g));
|
||||
new_g
|
||||
};
|
||||
|
||||
// NOTE: Alignment from attributes has already been applied to the allocation.
|
||||
set_global_alignment(self, g, alloc.align);
|
||||
llvm::set_initializer(g, v);
|
||||
|
||||
|
|
|
|||
|
|
@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
// # Global allocations
|
||||
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
|
||||
// NOTE: `static` alignment from attributes has already been applied to the allocation.
|
||||
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
|
||||
let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
|
||||
let kind = match global_alloc {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use tracing::debug;
|
||||
|
|
@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>(
|
|||
static_def_id: LocalDefId,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
|
||||
let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?;
|
||||
// Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating
|
||||
// the alignment attribute logic.
|
||||
let (size, align) =
|
||||
GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env);
|
||||
assert_eq!(size, layout.size);
|
||||
assert!(align >= layout.align.abi);
|
||||
|
||||
let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?;
|
||||
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
|
||||
assert_eq!(ecx.machine.static_root_ids, None);
|
||||
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
|
||||
|
|
|
|||
|
|
@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
|
||||
gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)),
|
||||
ungated!(
|
||||
unsafe(Edition2024) export_name, Normal,
|
||||
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
|
||||
|
|
|
|||
|
|
@ -632,6 +632,8 @@ declare_features! (
|
|||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
/// Allows specialization of implementations (RFC 1210).
|
||||
(incomplete, specialization, "1.7.0", Some(31844)),
|
||||
/// Allows using `#[rustc_align_static(...)]` on static items.
|
||||
(unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)),
|
||||
/// Allows attributes on expressions and non-item statements.
|
||||
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
|
|
|
|||
|
|
@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> {
|
|||
.expect("statics should not have generic parameters");
|
||||
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
|
||||
assert!(layout.is_sized());
|
||||
(layout.size, layout.align.abi)
|
||||
|
||||
// Take over-alignment from attributes into account.
|
||||
let align = match tcx.codegen_fn_attrs(def_id).alignment {
|
||||
Some(align_from_attribute) => {
|
||||
Ord::max(align_from_attribute, layout.align.abi)
|
||||
}
|
||||
None => layout.align.abi,
|
||||
};
|
||||
|
||||
(layout.size, align)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
|
|
|
|||
|
|
@ -501,6 +501,10 @@ passes_repr_align_should_be_align =
|
|||
`#[repr(align(...))]` is not supported on {$item}
|
||||
.help = use `#[rustc_align(...)]` instead
|
||||
|
||||
passes_repr_align_should_be_align_static =
|
||||
`#[repr(align(...))]` is not supported on {$item}
|
||||
.help = use `#[rustc_align_static(...)]` instead
|
||||
|
||||
passes_repr_conflicting =
|
||||
conflicting representation hints
|
||||
|
||||
|
|
|
|||
|
|
@ -1606,12 +1606,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
ReprAttr::ReprAlign(align) => {
|
||||
match target {
|
||||
Target::Struct | Target::Union | Target::Enum => {}
|
||||
Target::Fn | Target::Method(_) => {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1609,6 +1609,15 @@ pub(crate) struct ReprAlignShouldBeAlign {
|
|||
pub item: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_repr_align_should_be_align_static)]
|
||||
pub(crate) struct ReprAlignShouldBeAlignStatic {
|
||||
#[primary_span]
|
||||
#[help]
|
||||
pub span: Span,
|
||||
pub item: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_custom_mir_phase_requires_dialect)]
|
||||
pub(crate) struct CustomMirPhaseRequiresDialect {
|
||||
|
|
|
|||
|
|
@ -1848,6 +1848,7 @@ symbols! {
|
|||
rustc_abi,
|
||||
// FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity
|
||||
rustc_align,
|
||||
rustc_align_static,
|
||||
rustc_allocator,
|
||||
rustc_allocator_zeroed,
|
||||
rustc_allocator_zeroed_variant,
|
||||
|
|
@ -2099,6 +2100,7 @@ symbols! {
|
|||
staged_api,
|
||||
start,
|
||||
state,
|
||||
static_align,
|
||||
static_in_const,
|
||||
static_nobundle,
|
||||
static_recursion,
|
||||
|
|
|
|||
14
src/tools/miri/tests/pass/static_align.rs
Normal file
14
src/tools/miri/tests/pass/static_align.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#![feature(static_align)]
|
||||
|
||||
// When a static uses `align(N)`, its address should be a multiple of `N`.
|
||||
|
||||
#[rustc_align_static(256)]
|
||||
static FOO: u64 = 0;
|
||||
|
||||
#[rustc_align_static(512)]
|
||||
static BAR: u64 = 0;
|
||||
|
||||
fn main() {
|
||||
assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256));
|
||||
assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512));
|
||||
}
|
||||
31
tests/codegen-llvm/align-static.rs
Normal file
31
tests/codegen-llvm/align-static.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(static_align)]
|
||||
|
||||
// CHECK: @STATIC_ALIGN =
|
||||
// CHECK-SAME: align 16
|
||||
#[no_mangle]
|
||||
#[rustc_align_static(16)]
|
||||
pub static STATIC_ALIGN: u64 = 0;
|
||||
|
||||
// CHECK: @ALIGN_SPECIFIED_TWICE_1 =
|
||||
// CHECK-SAME: align 64
|
||||
#[no_mangle]
|
||||
#[rustc_align_static(32)]
|
||||
#[rustc_align_static(64)]
|
||||
pub static ALIGN_SPECIFIED_TWICE_1: u64 = 0;
|
||||
|
||||
// CHECK: @ALIGN_SPECIFIED_TWICE_2 =
|
||||
// CHECK-SAME: align 128
|
||||
#[no_mangle]
|
||||
#[rustc_align_static(128)]
|
||||
#[rustc_align_static(32)]
|
||||
pub static ALIGN_SPECIFIED_TWICE_2: u64 = 0;
|
||||
|
||||
// CHECK: @ALIGN_SPECIFIED_TWICE_3 =
|
||||
// CHECK-SAME: align 256
|
||||
#[no_mangle]
|
||||
#[rustc_align_static(32)]
|
||||
#[rustc_align_static(256)]
|
||||
pub static ALIGN_SPECIFIED_TWICE_3: u64 = 0;
|
||||
17
tests/ui/attributes/malformed-static-align.rs
Normal file
17
tests/ui/attributes/malformed-static-align.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(static_align)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[rustc_align_static = 16] //~ ERROR malformed `rustc_align_static` attribute input
|
||||
static S1: () = ();
|
||||
|
||||
#[rustc_align_static("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer
|
||||
static S2: () = ();
|
||||
|
||||
#[rustc_align_static(0)] //~ ERROR invalid alignment value: not a power of two
|
||||
static S3: () = ();
|
||||
|
||||
#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on static
|
||||
static S4: () = ();
|
||||
|
||||
#[rustc_align_static(16)] //~ ERROR `#[rustc_align_static]` attribute cannot be used on structs
|
||||
struct Struct1;
|
||||
45
tests/ui/attributes/malformed-static-align.stderr
Normal file
45
tests/ui/attributes/malformed-static-align.stderr
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
error[E0539]: malformed `rustc_align_static` attribute input
|
||||
--> $DIR/malformed-static-align.rs:4:1
|
||||
|
|
||||
LL | #[rustc_align_static = 16]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected this to be a list
|
||||
| help: must be of the form: `#[rustc_align_static(<alignment in bytes>)]`
|
||||
|
||||
error[E0589]: invalid alignment value: not an unsuffixed integer
|
||||
--> $DIR/malformed-static-align.rs:7:22
|
||||
|
|
||||
LL | #[rustc_align_static("hello")]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0589]: invalid alignment value: not a power of two
|
||||
--> $DIR/malformed-static-align.rs:10:22
|
||||
|
|
||||
LL | #[rustc_align_static(0)]
|
||||
| ^
|
||||
|
||||
error: `#[rustc_align_static]` attribute cannot be used on structs
|
||||
--> $DIR/malformed-static-align.rs:16:1
|
||||
|
|
||||
LL | #[rustc_align_static(16)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `#[rustc_align_static]` can be applied to statics and foreign statics
|
||||
|
||||
error: `#[repr(align(...))]` is not supported on statics
|
||||
--> $DIR/malformed-static-align.rs:13:8
|
||||
|
|
||||
LL | #[repr(align(16))]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
help: use `#[rustc_align_static(...)]` instead
|
||||
--> $DIR/malformed-static-align.rs:13:8
|
||||
|
|
||||
LL | #[repr(align(16))]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0539, E0589.
|
||||
For more information about an error, try `rustc --explain E0539`.
|
||||
11
tests/ui/feature-gates/feature-gate-static_align.rs
Normal file
11
tests/ui/feature-gates/feature-gate-static_align.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![crate_type = "lib"]
|
||||
|
||||
#[rustc_align_static(16)]
|
||||
//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature
|
||||
static REQUIRES_ALIGNMENT: u64 = 0;
|
||||
|
||||
extern "C" {
|
||||
#[rustc_align_static(16)]
|
||||
//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature
|
||||
static FOREIGN_STATIC: u32;
|
||||
}
|
||||
23
tests/ui/feature-gates/feature-gate-static_align.stderr
Normal file
23
tests/ui/feature-gates/feature-gate-static_align.stderr
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-static_align.rs:3:1
|
||||
|
|
||||
LL | #[rustc_align_static(16)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information
|
||||
= help: add `#![feature(static_align)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-static_align.rs:8:5
|
||||
|
|
||||
LL | #[rustc_align_static(16)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information
|
||||
= help: add `#![feature(static_align)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
26
tests/ui/static/static-align.rs
Normal file
26
tests/ui/static/static-align.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//@ run-pass
|
||||
#![feature(static_align)]
|
||||
|
||||
#[rustc_align_static(64)]
|
||||
static A: u8 = 0;
|
||||
|
||||
#[rustc_align_static(64)]
|
||||
static B: u8 = 0;
|
||||
|
||||
#[rustc_align_static(128)]
|
||||
#[no_mangle]
|
||||
static EXPORTED: u64 = 0;
|
||||
|
||||
unsafe extern "C" {
|
||||
#[rustc_align_static(128)]
|
||||
#[link_name = "EXPORTED"]
|
||||
static C: u64;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64));
|
||||
assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64));
|
||||
|
||||
assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128));
|
||||
unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue