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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,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,
Expand Down Expand Up @@ -149,6 +149,7 @@ attribute_parsers!(
pub(crate) static ATTRIBUTE_PARSERS = [
// tidy-alphabetical-start
AlignParser,
AlignStaticParser,
BodyStabilityParser,
ConfusablesParser,
ConstStabilityParser,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_gcc/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RalfJung this is where the attribute gets declared, and the feature name on this line (static_align in this case) must be unique

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's very odd, why does it have to be unique? That's not how features work anywhere else in the compiler, AFAIK.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, sorry, what I meant by unique is that an attribute must be tied to one unstable feature. #[rustc_align] is already tied to fn_align, so it can't also be used for static_align.

So, one unstable feature can "contain" multiple attributes, but an attribute always is tied to only one unstable feature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, by "attribute used for feature" you mean "attribute is gated by feature". That's a rather confusing and non-standard way of saying things.^^

So what you want is to have a separate feature gate for aligning functions vs aligning statics, and the attribute registration macro isn't flexible enough to allow that. rustc_align is for functions only, despite its name sounding more general.

Since these are all temporary names anyway, I guess it doesn't matter too much, but when it comes to stabilization we very much might need the ability to stabilize an attribute in some positions while leaving it unstable elsewhere. Otherwise we have no way of unstably extending where an existing stable attribute can be used. So this limitation of attribute feature gating seems like it could become problematic. Cc @jdonszelmann

ungated!(
unsafe(Edition2024) export_name, Normal,
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_middle/src/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1602,12 +1602,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,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,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,
Expand Down Expand Up @@ -2097,6 +2098,7 @@ symbols! {
staged_api,
start,
state,
static_align,
static_in_const,
static_nobundle,
static_recursion,
Expand Down
14 changes: 14 additions & 0 deletions src/tools/miri/tests/pass/static_align.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 31 additions & 0 deletions tests/codegen-llvm/align-static.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions tests/ui/attributes/malformed-static-align.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions tests/ui/attributes/malformed-static-align.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions tests/ui/feature-gates/feature-gate-static_align.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions tests/ui/feature-gates/feature-gate-static_align.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 26 additions & 0 deletions tests/ui/static/static-align.rs
Original file line number Diff line number Diff line change
@@ -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