Skip to content

Commit 448d076

Browse files
committed
Allow specifying alignment for functions
1 parent 138fd56 commit 448d076

File tree

18 files changed

+137
-83
lines changed

18 files changed

+137
-83
lines changed

compiler/rustc_attr/src/builtin.rs

+14-36
Original file line numberDiff line numberDiff line change
@@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
862862
if let Some(items) = attr.meta_item_list() {
863863
sess.mark_attr_used(attr);
864864
for item in items {
865-
if !item.is_meta_item() {
866-
handle_errors(
867-
&sess.parse_sess,
868-
item.span(),
869-
AttrError::UnsupportedLiteral(
870-
"meta item in `repr` must be an identifier",
871-
false,
872-
),
873-
);
874-
continue;
875-
}
876-
877865
let mut recognised = false;
878866
if item.is_word() {
879867
let hint = match item.name_or_empty() {
@@ -890,23 +878,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
890878
acc.push(h);
891879
}
892880
} else if let Some((name, value)) = item.name_value_literal() {
893-
let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
894-
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
895-
if literal.is_power_of_two() {
896-
// rustc_middle::ty::layout::Align restricts align to <= 2^29
897-
if *literal <= 1 << 29 {
898-
Ok(*literal as u32)
899-
} else {
900-
Err("larger than 2^29")
901-
}
902-
} else {
903-
Err("not a power of two")
904-
}
905-
} else {
906-
Err("not an unsuffixed integer")
907-
}
908-
};
909-
910881
let mut literal_error = None;
911882
if name == sym::align {
912883
recognised = true;
@@ -966,13 +937,7 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
966937
}
967938
if !recognised {
968939
// Not a word we recognize
969-
struct_span_err!(
970-
diagnostic,
971-
item.span(),
972-
E0552,
973-
"unrecognized representation hint"
974-
)
975-
.emit();
940+
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
976941
}
977942
}
978943
}
@@ -1080,3 +1045,16 @@ fn allow_unstable<'a>(
10801045
name
10811046
})
10821047
}
1048+
1049+
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
1050+
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
1051+
if literal.is_power_of_two() {
1052+
// rustc_middle::ty::layout::Align restricts align to <= 2^29
1053+
if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") }
1054+
} else {
1055+
Err("not a power of two")
1056+
}
1057+
} else {
1058+
Err("not an unsuffixed integer")
1059+
}
1060+
}

compiler/rustc_codegen_llvm/src/attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
279279
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
280280
llvm::AddFunctionAttrString(llfn, Function, cstr!("cmse_nonsecure_entry"));
281281
}
282+
if let Some(align) = codegen_fn_attrs.alignment {
283+
llvm::set_alignment(llfn, align as usize);
284+
}
282285
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
283286

284287
// Always annotate functions with the target-cpu they are compiled for.

compiler/rustc_feature/src/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,9 @@ declare_features! (
645645
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
646646
(active, c_unwind, "1.52.0", Some(74990), None),
647647

648+
/// Allows using `#[repr(align(...))]` on function items
649+
(active, fn_align, "1.53.0", Some(82232), None),
650+
648651
// -------------------------------------------------------------------------
649652
// feature-group-end: actual feature gates
650653
// -------------------------------------------------------------------------

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pub struct CodegenFnAttrs {
3838
/// be generated against a specific instruction set. Only usable on architectures which allow
3939
/// switching between multiple instruction sets.
4040
pub instruction_set: Option<InstructionSetAttr>,
41+
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
42+
/// aligned to.
43+
pub alignment: Option<u32>,
4144
}
4245

4346
bitflags! {
@@ -103,6 +106,7 @@ impl CodegenFnAttrs {
103106
link_section: None,
104107
no_sanitize: SanitizerSet::empty(),
105108
instruction_set: None,
109+
alignment: None,
106110
}
107111
}
108112

compiler/rustc_passes/src/check_attr.rs

+40-6
Original file line numberDiff line numberDiff line change
@@ -1127,17 +1127,41 @@ impl CheckAttrVisitor<'tcx> {
11271127
let mut is_transparent = false;
11281128

11291129
for hint in &hints {
1130+
if !hint.is_meta_item() {
1131+
struct_span_err!(
1132+
self.tcx.sess,
1133+
hint.span(),
1134+
E0565,
1135+
"meta item in `repr` must be an identifier"
1136+
)
1137+
.emit();
1138+
continue;
1139+
}
1140+
11301141
let (article, allowed_targets) = match hint.name_or_empty() {
1131-
_ if !matches!(target, Target::Struct | Target::Enum | Target::Union) => {
1132-
("a", "struct, enum, or union")
1133-
}
1134-
name @ sym::C | name @ sym::align => {
1135-
is_c |= name == sym::C;
1142+
sym::C => {
1143+
is_c = true;
11361144
match target {
11371145
Target::Struct | Target::Union | Target::Enum => continue,
11381146
_ => ("a", "struct, enum, or union"),
11391147
}
11401148
}
1149+
sym::align => {
1150+
if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) {
1151+
feature_err(
1152+
&self.tcx.sess.parse_sess,
1153+
sym::fn_align,
1154+
hint.span(),
1155+
"`repr(align)` attributes on functions are unstable",
1156+
)
1157+
.emit();
1158+
}
1159+
1160+
match target {
1161+
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
1162+
_ => ("a", "struct, enum, function, or union"),
1163+
}
1164+
}
11411165
sym::packed => {
11421166
if target != Target::Struct && target != Target::Union {
11431167
("a", "struct or union")
@@ -1194,7 +1218,17 @@ impl CheckAttrVisitor<'tcx> {
11941218
continue;
11951219
}
11961220
}
1197-
_ => continue,
1221+
_ => {
1222+
struct_span_err!(
1223+
self.tcx.sess,
1224+
hint.span(),
1225+
E0552,
1226+
"unrecognized representation hint"
1227+
)
1228+
.emit();
1229+
1230+
continue;
1231+
}
11981232
};
11991233

12001234
struct_span_err!(

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ symbols! {
561561
fmt,
562562
fmt_internals,
563563
fmul_fast,
564+
fn_align,
564565
fn_must_use,
565566
fn_mut,
566567
fn_once,

compiler/rustc_typeck/src/collect.rs

+32
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
//! At present, however, we do run collection across all items in the
1616
//! crate as a kind of pass. This should eventually be factored away.
1717
18+
// ignore-tidy-filelength
19+
1820
use crate::astconv::{AstConv, SizedByDefault};
1921
use crate::bounds::Bounds;
2022
use crate::check::intrinsic::intrinsic_operation_unsafety;
@@ -2884,6 +2886,36 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
28842886
None
28852887
}
28862888
};
2889+
} else if tcx.sess.check_name(attr, sym::repr) {
2890+
codegen_fn_attrs.alignment = match attr.meta_item_list() {
2891+
Some(items) => match items.as_slice() {
2892+
[item] => match item.name_value_literal() {
2893+
Some((sym::align, literal)) => {
2894+
let alignment = rustc_attr::parse_alignment(&literal.kind);
2895+
2896+
match alignment {
2897+
Ok(align) => Some(align),
2898+
Err(msg) => {
2899+
struct_span_err!(
2900+
tcx.sess.diagnostic(),
2901+
attr.span,
2902+
E0589,
2903+
"invalid `repr(align)` attribute: {}",
2904+
msg
2905+
)
2906+
.emit();
2907+
2908+
None
2909+
}
2910+
}
2911+
}
2912+
_ => None,
2913+
},
2914+
[] => None,
2915+
_ => None,
2916+
},
2917+
None => None,
2918+
};
28872919
}
28882920
}
28892921

src/test/codegen/align-fn.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
2+
3+
#![crate_type = "lib"]
4+
#![feature(fn_align)]
5+
6+
// CHECK: align 16
7+
#[no_mangle]
8+
#[repr(align(16))]
9+
pub fn fn_align() {}

src/test/ui/attributes/nonterminal-expansion.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
macro_rules! pass_nonterminal {
44
($n:expr) => {
55
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
6-
//~| ERROR unrecognized representation hint
76
struct S;
87
};
98
}

src/test/ui/attributes/nonterminal-expansion.stderr

+1-13
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,5 @@ LL | pass_nonterminal!(n!());
99
|
1010
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
1111

12-
error[E0552]: unrecognized representation hint
13-
--> $DIR/nonterminal-expansion.rs:5:16
14-
|
15-
LL | #[repr(align($n))]
16-
| ^^^^^^^^^
17-
...
18-
LL | pass_nonterminal!(n!());
19-
| ------------------------ in this macro invocation
20-
|
21-
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
22-
23-
error: aborting due to 2 previous errors
12+
error: aborting due to previous error
2413

25-
For more information about this error, try `rustc --explain E0552`.

src/test/ui/error-codes/E0565.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// repr currently doesn't support literals
22
#[repr("C")] //~ ERROR E0565
3-
//~| ERROR E0565
4-
struct A { }
3+
struct A {}
54

6-
fn main() { }
5+
fn main() {}

src/test/ui/error-codes/E0565.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ error[E0565]: meta item in `repr` must be an identifier
44
LL | #[repr("C")]
55
| ^^^
66

7-
error[E0565]: meta item in `repr` must be an identifier
8-
--> $DIR/E0565.rs:2:8
9-
|
10-
LL | #[repr("C")]
11-
| ^^^
12-
13-
error: aborting due to 2 previous errors
7+
error: aborting due to previous error
148

159
For more information about this error, try `rustc --explain E0565`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![crate_type = "lib"]
2+
3+
#[repr(align(16))] //~ ERROR `repr(align)` attributes on functions are unstable
4+
fn requires_alignment() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: `repr(align)` attributes on functions are unstable
2+
--> $DIR/feature-gate-fn_align.rs:3:8
3+
|
4+
LL | #[repr(align(16))]
5+
| ^^^^^^^^^
6+
|
7+
= note: see issue #82232 <https://github.com/rust-lang/rust/issues/82232> for more information
8+
= help: add `#![feature(fn_align)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

src/test/ui/issues/issue-43988.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ fn main() {
1313

1414
#[repr(nothing)]
1515
let _x = 0;
16-
//~^^ ERROR attribute should be applied to a struct, enum, or union
16+
//~^^ ERROR E0552
1717

1818
#[repr(something_not_real)]
1919
loop {
2020
()
2121
};
22-
//~^^^^ ERROR attribute should be applied to a struct, enum, or union
22+
//~^^^^ ERROR E0552
2323

2424
#[repr]
2525
let _y = "123";

src/test/ui/issues/issue-43988.stderr

+6-12
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,17 @@ LL | #[inline(XYZ)]
2626
LL | let _b = 4;
2727
| ----------- not a function or closure
2828

29-
error[E0517]: attribute should be applied to a struct, enum, or union
29+
error[E0552]: unrecognized representation hint
3030
--> $DIR/issue-43988.rs:14:12
3131
|
3232
LL | #[repr(nothing)]
3333
| ^^^^^^^
34-
LL | let _x = 0;
35-
| ----------- not a struct, enum, or union
3634

37-
error[E0517]: attribute should be applied to a struct, enum, or union
35+
error[E0552]: unrecognized representation hint
3836
--> $DIR/issue-43988.rs:18:12
3937
|
40-
LL | #[repr(something_not_real)]
41-
| ^^^^^^^^^^^^^^^^^^
42-
LL | / loop {
43-
LL | | ()
44-
LL | | };
45-
| |_____- not a struct, enum, or union
38+
LL | #[repr(something_not_real)]
39+
| ^^^^^^^^^^^^^^^^^^
4640

4741
error[E0518]: attribute should be applied to function or closure
4842
--> $DIR/issue-43988.rs:30:5
@@ -54,5 +48,5 @@ LL | foo();
5448

5549
error: aborting due to 7 previous errors
5650

57-
Some errors have detailed explanations: E0517, E0518.
58-
For more information about an error, try `rustc --explain E0517`.
51+
Some errors have detailed explanations: E0518, E0552.
52+
For more information about an error, try `rustc --explain E0518`.

src/test/ui/repr/repr-disallow-on-variant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ struct Test;
22

33
enum Foo {
44
#[repr(u8)]
5-
//~^ ERROR attribute should be applied to a struct, enum, or union
5+
//~^ ERROR attribute should be applied to an enum
66
Variant,
77
}
88

src/test/ui/repr/repr-disallow-on-variant.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0517]: attribute should be applied to a struct, enum, or union
1+
error[E0517]: attribute should be applied to an enum
22
--> $DIR/repr-disallow-on-variant.rs:4:12
33
|
44
LL | #[repr(u8)]
55
| ^^
66
LL |
77
LL | Variant,
8-
| ------- not a struct, enum, or union
8+
| ------- not an enum
99

1010
error: aborting due to previous error
1111

0 commit comments

Comments
 (0)