about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorTrevor Gross <t.gross35@gmail.com>2025-06-18 20:22:49 -0400
committerGitHub <noreply@github.com>2025-06-18 20:22:49 -0400
commit07932ad11153b62ec2138fa71a398a1ca8ea05ac (patch)
tree289f0c510ce9d472d6c5e29424f3174fe7ac71b9 /compiler
parentcff8e9ae142c3dcaf4c66ec5b6be932f1442c4b5 (diff)
parent1fdf2b562070ec98c5b32ee67b8c6d8145127a6e (diff)
downloadrust-07932ad11153b62ec2138fa71a398a1ca8ea05ac.tar.gz
rust-07932ad11153b62ec2138fa71a398a1ca8ea05ac.zip
Rollup merge of #142507 - folkertdev:fn-align-align-attribute, r=jdonszelmann
use `#[align]` attribute for `fn_align`

Tracking issue: https://github.com/rust-lang/rust/issues/82232

https://github.com/rust-lang/rfcs/pull/3806 decides to add the `#[align]` attribute for alignment of various items. Right now it's used for functions with `fn_align`, in the future it will get more uses (statics, struct fields, etc.)

(the RFC finishes FCP today)

r? `@ghost`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs3
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs58
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs14
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs3
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_passes/messages.ftl15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs75
-rw-r--r--compiler/rustc_passes/src/errors.rs30
12 files changed, 154 insertions, 60 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index d4c43456049..cdc01dc6c91 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -182,6 +182,9 @@ impl Deprecation {
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
 pub enum AttributeKind {
     // tidy-alphabetical-start
+    /// Represents `#[align(N)]`.
+    Align { align: Align, span: Span },
+
     /// Represents `#[rustc_allow_const_fn_unstable]`.
     AllowConstFnUnstable(ThinVec<Symbol>),
 
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index b9b386635f6..0891afc003e 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -44,6 +44,9 @@ attr_parsing_incorrect_repr_format_packed_expect_integer =
 attr_parsing_incorrect_repr_format_packed_one_or_zero_arg =
     incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
 
+attr_parsing_invalid_alignment_value =
+    invalid alignment value: {$error_part}
+
 attr_parsing_invalid_issue_string =
     `issue` must be a non-zero numeric string or "none"
     .must_not_be_zero = `issue` must not be "0", use "none" instead
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index ae9e7871874..c9f9f34bdb7 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
 use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
-use super::{CombineAttributeParser, ConvertFn};
+use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext};
 use crate::context::{AcceptContext, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
 use crate::session_diagnostics;
@@ -203,7 +203,7 @@ fn parse_repr_align<S: Stage>(
                 });
             }
             Align => {
-                cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
+                cx.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
                     span: param_span,
                 });
             }
@@ -266,3 +266,57 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
         Err("not an unsuffixed integer")
     }
 }
+
+/// Parse #[align(N)].
+#[derive(Default)]
+pub(crate) struct AlignParser(Option<(Align, Span)>);
+
+impl AlignParser {
+    const PATH: &'static [Symbol] = &[sym::align];
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "<alignment in bytes>");
+
+    fn parse<'c, S: Stage>(
+        &mut self,
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) {
+        match args {
+            ArgParser::NoArgs | ArgParser::NameValue(_) => {
+                cx.expected_list(cx.attr_span);
+            }
+            ArgParser::List(list) => {
+                let Some(align) = list.single() else {
+                    cx.expected_single_argument(list.span);
+                    return;
+                };
+
+                let Some(lit) = align.lit() else {
+                    cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
+                        span: align.span(),
+                    });
+
+                    return;
+                };
+
+                match parse_alignment(&lit.kind) {
+                    Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))),
+                    Err(message) => {
+                        cx.emit_err(session_diagnostics::InvalidAlignmentValue {
+                            span: lit.span,
+                            error_part: message,
+                        });
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<S: Stage> AttributeParser<S> for AlignParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        let (align, span) = self.0?;
+        Some(AttributeKind::Align { align, span })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 51c1760da30..d7570634c1f 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -19,7 +19,7 @@ use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
 use crate::attributes::lint_helpers::AsPtrParser;
-use crate::attributes::repr::ReprParser;
+use crate::attributes::repr::{AlignParser, ReprParser};
 use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
 };
@@ -90,6 +90,7 @@ macro_rules! attribute_parsers {
 attribute_parsers!(
     pub(crate) static ATTRIBUTE_PARSERS = [
         // tidy-alphabetical-start
+        AlignParser,
         BodyStabilityParser,
         ConfusablesParser,
         ConstStabilityParser,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 57ac92a0ca1..337921a318c 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -451,6 +451,14 @@ pub(crate) struct EmptyConfusables {
 }
 
 #[derive(Diagnostic)]
+#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
+pub(crate) struct InvalidAlignmentValue {
+    #[primary_span]
+    pub span: Span,
+    pub error_part: &'static str,
+}
+
+#[derive(Diagnostic)]
 #[diag(attr_parsing_repr_ident, code = E0565)]
 pub(crate) struct ReprIdent {
     #[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 188a9a98ce7..98742255063 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -3,7 +3,6 @@ use std::str::FromStr;
 use rustc_abi::ExternAbi;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
-use rustc_attr_data_structures::ReprAttr::ReprAlign;
 use rustc_attr_data_structures::{
     AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
 };
@@ -110,17 +109,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             }
         };
 
-        if let hir::Attribute::Parsed(p) = attr {
-            match p {
-                AttributeKind::Repr(reprs) => {
-                    codegen_fn_attrs.alignment = reprs
-                        .iter()
-                        .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
-                        .max();
-                }
-
-                _ => {}
-            }
+        if let hir::Attribute::Parsed(AttributeKind::Align { align, .. }) = attr {
+            codegen_fn_attrs.alignment = Some(*align);
         }
 
         let Some(Ident { name, .. }) = attr.ident() else {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b5218ec267c..5b1f1684d54 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -495,6 +495,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
+    gated!(align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(align)),
     ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
     ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
     ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index f21cf5fa45e..2f16d385efb 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -47,8 +47,7 @@ pub struct CodegenFnAttrs {
     /// be generated against a specific instruction set. Only usable on architectures which allow
     /// switching between multiple instruction sets.
     pub instruction_set: Option<InstructionSetAttr>,
-    /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
-    /// aligned to.
+    /// The `#[align(...)]` attribute. Determines the alignment of the function body.
     pub alignment: Option<Align>,
     /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
     /// the function entry.
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index b3096e46b09..a12215a44f9 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -289,6 +289,7 @@ fn emit_malformed_attribute(
             | sym::rustc_force_inline
             | sym::rustc_confusables
             | sym::repr
+            | sym::align
             | sym::deprecated
     ) {
         return;
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 7c237d708c0..c1a2b3b2973 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -13,6 +13,10 @@ passes_abi_ne =
 passes_abi_of =
     fn_abi_of({$fn_name}) = {$fn_abi}
 
+passes_align_should_be_repr_align =
+    `#[align(...)]` is not supported on {$item} items
+    .suggestion = use `#[repr(align(...))]` instead
+
 passes_allow_incoherent_impl =
     `rustc_allow_incoherent_impl` attribute should be applied to impl items
     .label = the only currently supported targets are inherent methods
@@ -29,10 +33,6 @@ passes_attr_application_struct =
     attribute should be applied to a struct
     .label = not a struct
 
-passes_attr_application_struct_enum_function_method_union =
-    attribute should be applied to a struct, enum, function, associated function, or union
-    .label = not a struct, enum, function, associated function, or union
-
 passes_attr_application_struct_enum_union =
     attribute should be applied to a struct, enum, or union
     .label = not a struct, enum, or union
@@ -583,13 +583,14 @@ passes_remove_fields =
      *[other] 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_align_should_be_align =
+    `#[repr(align(...))]` is not supported on {$item} items
+    .help = use `#[align(...)]` instead
+
 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 5ce803aa1f8..50d6c5d9764 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -146,6 +146,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 }
                 Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */
                 }
+                Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
+                    self.check_align(span, target, *align, *repr_span)
+                }
+
                 Attribute::Parsed(
                     AttributeKind::BodyStability { .. }
                     | AttributeKind::ConstStabilityIndirect
@@ -643,6 +647,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             sym::naked,
             sym::instruction_set,
             sym::repr,
+            sym::align,
             sym::rustc_std_internal_symbol,
             // code generation
             sym::cold,
@@ -679,7 +684,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     // this check can be part of the parser and be removed here
                     match other_attr {
                         Attribute::Parsed(
-                            AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. },
+                            AttributeKind::Deprecation { .. }
+                            | AttributeKind::Repr { .. }
+                            | AttributeKind::Align { .. },
                         ) => {
                             continue;
                         }
@@ -1964,6 +1971,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    /// Checks if the `#[align]` attributes on `item` are valid.
+    fn check_align(&self, span: Span, target: Target, align: Align, repr_span: Span) {
+        match target {
+            Target::Fn | Target::Method(_) => {}
+            Target::Struct | Target::Union | Target::Enum => {
+                self.dcx().emit_err(errors::AlignShouldBeReprAlign {
+                    span: repr_span,
+                    item: target.name(),
+                    align_bytes: align.bytes(),
+                });
+            }
+            _ => {
+                self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
+                    hint_span: repr_span,
+                    span,
+                });
+            }
+        }
+
+        self.check_align_value(align, repr_span);
+    }
+
     /// Checks if the `#[repr]` attributes on `item` are valid.
     fn check_repr(
         &self,
@@ -2016,23 +2045,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     match target {
                         Target::Struct | Target::Union | Target::Enum => {}
                         Target::Fn | Target::Method(_) => {
-                            if !self.tcx.features().fn_align() {
-                                feature_err(
-                                    &self.tcx.sess,
-                                    sym::fn_align,
-                                    *repr_span,
-                                    fluent::passes_repr_align_function,
-                                )
-                                .emit();
-                            }
+                            self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
+                                span: *repr_span,
+                                item: target.name(),
+                            });
                         }
                         _ => {
-                            self.dcx().emit_err(
-                                errors::AttrApplication::StructEnumFunctionMethodUnion {
-                                    hint_span: *repr_span,
-                                    span,
-                                },
-                            );
+                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
+                                hint_span: *repr_span,
+                                span,
+                            });
                         }
                     }
 
@@ -2090,21 +2112,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         match target {
                             Target::Struct | Target::Union | Target::Enum => continue,
                             Target::Fn | Target::Method(_) => {
-                                feature_err(
-                                    &self.tcx.sess,
-                                    sym::fn_align,
-                                    *repr_span,
-                                    fluent::passes_repr_align_function,
-                                )
-                                .emit();
+                                self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
+                                    span: *repr_span,
+                                    item: target.name(),
+                                });
                             }
                             _ => {
-                                self.dcx().emit_err(
-                                    errors::AttrApplication::StructEnumFunctionMethodUnion {
-                                        hint_span: *repr_span,
-                                        span,
-                                    },
-                                );
+                                self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
+                                    hint_span: *repr_span,
+                                    span,
+                                });
                             }
                         }
                     }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index f0d4b610f63..587d9170f06 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1308,13 +1308,6 @@ pub(crate) enum AttrApplication {
         #[label]
         span: Span,
     },
-    #[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)]
-    StructEnumFunctionMethodUnion {
-        #[primary_span]
-        hint_span: Span,
-        #[label]
-        span: Span,
-    },
 }
 
 #[derive(Diagnostic)]
@@ -1816,3 +1809,26 @@ pub(crate) enum UnexportableItem<'a> {
         field_name: &'a str,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(passes_repr_align_should_be_align)]
+pub(crate) struct ReprAlignShouldBeAlign {
+    #[primary_span]
+    #[help]
+    pub span: Span,
+    pub item: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_align_should_be_repr_align)]
+pub(crate) struct AlignShouldBeReprAlign {
+    #[primary_span]
+    #[suggestion(
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "#[repr(align({align_bytes}))]"
+    )]
+    pub span: Span,
+    pub item: &'static str,
+    pub align_bytes: u64,
+}