Skip to content

Commit 1fdf2b5

Browse files
committed
add #[align] attribute
Right now it's used for functions with `fn_align`, in the future it will get more uses (statics, struct fields, etc.)
1 parent 1bb3352 commit 1fdf2b5

30 files changed

+320
-133
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ impl Deprecation {
182182
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
183183
pub enum AttributeKind {
184184
// tidy-alphabetical-start
185+
/// Represents `#[align(N)]`.
186+
Align { align: Align, span: Span },
187+
185188
/// Represents `#[rustc_allow_const_fn_unstable]`.
186189
AllowConstFnUnstable(ThinVec<Symbol>),
187190

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ attr_parsing_incorrect_repr_format_packed_expect_integer =
4444
attr_parsing_incorrect_repr_format_packed_one_or_zero_arg =
4545
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
4646
47+
attr_parsing_invalid_alignment_value =
48+
invalid alignment value: {$error_part}
49+
4750
attr_parsing_invalid_issue_string =
4851
`issue` must be a non-zero numeric string or "none"
4952
.must_not_be_zero = `issue` must not be "0", use "none" instead

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
44
use rustc_feature::{AttributeTemplate, template};
55
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
66

7-
use super::{CombineAttributeParser, ConvertFn};
7+
use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext};
88
use crate::context::{AcceptContext, Stage};
99
use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
1010
use crate::session_diagnostics;
@@ -203,7 +203,7 @@ fn parse_repr_align<S: Stage>(
203203
});
204204
}
205205
Align => {
206-
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
206+
cx.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
207207
span: param_span,
208208
});
209209
}
@@ -266,3 +266,57 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
266266
Err("not an unsuffixed integer")
267267
}
268268
}
269+
270+
/// Parse #[align(N)].
271+
#[derive(Default)]
272+
pub(crate) struct AlignParser(Option<(Align, Span)>);
273+
274+
impl AlignParser {
275+
const PATH: &'static [Symbol] = &[sym::align];
276+
const TEMPLATE: AttributeTemplate = template!(Word, List: "<alignment in bytes>");
277+
278+
fn parse<'c, S: Stage>(
279+
&mut self,
280+
cx: &'c mut AcceptContext<'_, '_, S>,
281+
args: &'c ArgParser<'_>,
282+
) {
283+
match args {
284+
ArgParser::NoArgs | ArgParser::NameValue(_) => {
285+
cx.expected_list(cx.attr_span);
286+
}
287+
ArgParser::List(list) => {
288+
let Some(align) = list.single() else {
289+
cx.expected_single_argument(list.span);
290+
return;
291+
};
292+
293+
let Some(lit) = align.lit() else {
294+
cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
295+
span: align.span(),
296+
});
297+
298+
return;
299+
};
300+
301+
match parse_alignment(&lit.kind) {
302+
Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))),
303+
Err(message) => {
304+
cx.emit_err(session_diagnostics::InvalidAlignmentValue {
305+
span: lit.span,
306+
error_part: message,
307+
});
308+
}
309+
}
310+
}
311+
}
312+
}
313+
}
314+
315+
impl<S: Stage> AttributeParser<S> for AlignParser {
316+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
317+
318+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
319+
let (align, span) = self.0?;
320+
Some(AttributeKind::Align { align, span })
321+
}
322+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::attributes::confusables::ConfusablesParser;
1919
use crate::attributes::deprecation::DeprecationParser;
2020
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
2121
use crate::attributes::lint_helpers::AsPtrParser;
22-
use crate::attributes::repr::ReprParser;
22+
use crate::attributes::repr::{AlignParser, ReprParser};
2323
use crate::attributes::stability::{
2424
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
2525
};
@@ -90,6 +90,7 @@ macro_rules! attribute_parsers {
9090
attribute_parsers!(
9191
pub(crate) static ATTRIBUTE_PARSERS = [
9292
// tidy-alphabetical-start
93+
AlignParser,
9394
BodyStabilityParser,
9495
ConfusablesParser,
9596
ConstStabilityParser,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,14 @@ pub(crate) struct EmptyConfusables {
450450
pub span: Span,
451451
}
452452

453+
#[derive(Diagnostic)]
454+
#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
455+
pub(crate) struct InvalidAlignmentValue {
456+
#[primary_span]
457+
pub span: Span,
458+
pub error_part: &'static str,
459+
}
460+
453461
#[derive(Diagnostic)]
454462
#[diag(attr_parsing_repr_ident, code = E0565)]
455463
pub(crate) struct ReprIdent {

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::str::FromStr;
33
use rustc_abi::ExternAbi;
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
6-
use rustc_attr_data_structures::ReprAttr::ReprAlign;
76
use rustc_attr_data_structures::{
87
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
98
};
@@ -110,17 +109,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
110109
}
111110
};
112111

113-
if let hir::Attribute::Parsed(p) = attr {
114-
match p {
115-
AttributeKind::Repr(reprs) => {
116-
codegen_fn_attrs.alignment = reprs
117-
.iter()
118-
.filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
119-
.max();
120-
}
121-
122-
_ => {}
123-
}
112+
if let hir::Attribute::Parsed(AttributeKind::Align { align, .. }) = attr {
113+
codegen_fn_attrs.alignment = Some(*align);
124114
}
125115

126116
let Some(Ident { name, .. }) = attr.ident() else {

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
495495
),
496496
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
497497
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
498+
gated!(align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(align)),
498499
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
499500
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
500501
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ pub struct CodegenFnAttrs {
4747
/// be generated against a specific instruction set. Only usable on architectures which allow
4848
/// switching between multiple instruction sets.
4949
pub instruction_set: Option<InstructionSetAttr>,
50-
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
51-
/// aligned to.
50+
/// The `#[align(...)]` attribute. Determines the alignment of the function body.
5251
pub alignment: Option<Align>,
5352
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
5453
/// the function entry.

compiler/rustc_parse/src/validate_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ fn emit_malformed_attribute(
289289
| sym::rustc_force_inline
290290
| sym::rustc_confusables
291291
| sym::repr
292+
| sym::align
292293
| sym::deprecated
293294
) {
294295
return;

compiler/rustc_passes/messages.ftl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ passes_abi_ne =
1313
passes_abi_of =
1414
fn_abi_of({$fn_name}) = {$fn_abi}
1515
16+
passes_align_should_be_repr_align =
17+
`#[align(...)]` is not supported on {$item} items
18+
.suggestion = use `#[repr(align(...))]` instead
19+
1620
passes_allow_incoherent_impl =
1721
`rustc_allow_incoherent_impl` attribute should be applied to impl items
1822
.label = the only currently supported targets are inherent methods
@@ -29,10 +33,6 @@ passes_attr_application_struct =
2933
attribute should be applied to a struct
3034
.label = not a struct
3135
32-
passes_attr_application_struct_enum_function_method_union =
33-
attribute should be applied to a struct, enum, function, associated function, or union
34-
.label = not a struct, enum, function, associated function, or union
35-
3636
passes_attr_application_struct_enum_union =
3737
attribute should be applied to a struct, enum, or union
3838
.label = not a struct, enum, or union
@@ -583,13 +583,14 @@ passes_remove_fields =
583583
*[other] fields
584584
}
585585
586-
passes_repr_align_function =
587-
`repr(align)` attributes on functions are unstable
588-
589586
passes_repr_align_greater_than_target_max =
590587
alignment must not be greater than `isize::MAX` bytes
591588
.note = `isize::MAX` is {$size} for the current target
592589
590+
passes_repr_align_should_be_align =
591+
`#[repr(align(...))]` is not supported on {$item} items
592+
.help = use `#[align(...)]` instead
593+
593594
passes_repr_conflicting =
594595
conflicting representation hints
595596

compiler/rustc_passes/src/check_attr.rs

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
146146
}
147147
Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */
148148
}
149+
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
150+
self.check_align(span, target, *align, *repr_span)
151+
}
152+
149153
Attribute::Parsed(
150154
AttributeKind::BodyStability { .. }
151155
| AttributeKind::ConstStabilityIndirect
@@ -643,6 +647,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
643647
sym::naked,
644648
sym::instruction_set,
645649
sym::repr,
650+
sym::align,
646651
sym::rustc_std_internal_symbol,
647652
// code generation
648653
sym::cold,
@@ -679,7 +684,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
679684
// this check can be part of the parser and be removed here
680685
match other_attr {
681686
Attribute::Parsed(
682-
AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. },
687+
AttributeKind::Deprecation { .. }
688+
| AttributeKind::Repr { .. }
689+
| AttributeKind::Align { .. },
683690
) => {
684691
continue;
685692
}
@@ -1964,6 +1971,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19641971
}
19651972
}
19661973

1974+
/// Checks if the `#[align]` attributes on `item` are valid.
1975+
fn check_align(&self, span: Span, target: Target, align: Align, repr_span: Span) {
1976+
match target {
1977+
Target::Fn | Target::Method(_) => {}
1978+
Target::Struct | Target::Union | Target::Enum => {
1979+
self.dcx().emit_err(errors::AlignShouldBeReprAlign {
1980+
span: repr_span,
1981+
item: target.name(),
1982+
align_bytes: align.bytes(),
1983+
});
1984+
}
1985+
_ => {
1986+
self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1987+
hint_span: repr_span,
1988+
span,
1989+
});
1990+
}
1991+
}
1992+
1993+
self.check_align_value(align, repr_span);
1994+
}
1995+
19671996
/// Checks if the `#[repr]` attributes on `item` are valid.
19681997
fn check_repr(
19691998
&self,
@@ -2016,23 +2045,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
20162045
match target {
20172046
Target::Struct | Target::Union | Target::Enum => {}
20182047
Target::Fn | Target::Method(_) => {
2019-
if !self.tcx.features().fn_align() {
2020-
feature_err(
2021-
&self.tcx.sess,
2022-
sym::fn_align,
2023-
*repr_span,
2024-
fluent::passes_repr_align_function,
2025-
)
2026-
.emit();
2027-
}
2048+
self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
2049+
span: *repr_span,
2050+
item: target.name(),
2051+
});
20282052
}
20292053
_ => {
2030-
self.dcx().emit_err(
2031-
errors::AttrApplication::StructEnumFunctionMethodUnion {
2032-
hint_span: *repr_span,
2033-
span,
2034-
},
2035-
);
2054+
self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
2055+
hint_span: *repr_span,
2056+
span,
2057+
});
20362058
}
20372059
}
20382060

@@ -2090,21 +2112,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
20902112
match target {
20912113
Target::Struct | Target::Union | Target::Enum => continue,
20922114
Target::Fn | Target::Method(_) => {
2093-
feature_err(
2094-
&self.tcx.sess,
2095-
sym::fn_align,
2096-
*repr_span,
2097-
fluent::passes_repr_align_function,
2098-
)
2099-
.emit();
2115+
self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
2116+
span: *repr_span,
2117+
item: target.name(),
2118+
});
21002119
}
21012120
_ => {
2102-
self.dcx().emit_err(
2103-
errors::AttrApplication::StructEnumFunctionMethodUnion {
2104-
hint_span: *repr_span,
2105-
span,
2106-
},
2107-
);
2121+
self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
2122+
hint_span: *repr_span,
2123+
span,
2124+
});
21082125
}
21092126
}
21102127
}

compiler/rustc_passes/src/errors.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,13 +1308,6 @@ pub(crate) enum AttrApplication {
13081308
#[label]
13091309
span: Span,
13101310
},
1311-
#[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)]
1312-
StructEnumFunctionMethodUnion {
1313-
#[primary_span]
1314-
hint_span: Span,
1315-
#[label]
1316-
span: Span,
1317-
},
13181311
}
13191312

13201313
#[derive(Diagnostic)]
@@ -1816,3 +1809,26 @@ pub(crate) enum UnexportableItem<'a> {
18161809
field_name: &'a str,
18171810
},
18181811
}
1812+
1813+
#[derive(Diagnostic)]
1814+
#[diag(passes_repr_align_should_be_align)]
1815+
pub(crate) struct ReprAlignShouldBeAlign {
1816+
#[primary_span]
1817+
#[help]
1818+
pub span: Span,
1819+
pub item: &'static str,
1820+
}
1821+
1822+
#[derive(Diagnostic)]
1823+
#[diag(passes_align_should_be_repr_align)]
1824+
pub(crate) struct AlignShouldBeReprAlign {
1825+
#[primary_span]
1826+
#[suggestion(
1827+
style = "verbose",
1828+
applicability = "machine-applicable",
1829+
code = "#[repr(align({align_bytes}))]"
1830+
)]
1831+
pub span: Span,
1832+
pub item: &'static str,
1833+
pub align_bytes: u64,
1834+
}

0 commit comments

Comments
 (0)