mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #81234 - repnop:fn-alignment, r=lcnr
Allow specifying alignment for functions Fixes #75072 This allows the user to specify alignment for functions, which can be useful for low level work where functions need to necessarily be aligned to a specific value. I believe the error cases not covered in the match are caught earlier based on my testing so I had them just return `None`.
This commit is contained in:
commit
a6e7a5aa5d
@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
|||||||
if let Some(items) = attr.meta_item_list() {
|
if let Some(items) = attr.meta_item_list() {
|
||||||
sess.mark_attr_used(attr);
|
sess.mark_attr_used(attr);
|
||||||
for item in items {
|
for item in items {
|
||||||
if !item.is_meta_item() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
item.span(),
|
|
||||||
AttrError::UnsupportedLiteral(
|
|
||||||
"meta item in `repr` must be an identifier",
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut recognised = false;
|
let mut recognised = false;
|
||||||
if item.is_word() {
|
if item.is_word() {
|
||||||
let hint = match item.name_or_empty() {
|
let hint = match item.name_or_empty() {
|
||||||
@ -890,23 +878,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
|||||||
acc.push(h);
|
acc.push(h);
|
||||||
}
|
}
|
||||||
} else if let Some((name, value)) = item.name_value_literal() {
|
} else if let Some((name, value)) = item.name_value_literal() {
|
||||||
let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
|
|
||||||
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
|
|
||||||
if literal.is_power_of_two() {
|
|
||||||
// rustc_middle::ty::layout::Align restricts align to <= 2^29
|
|
||||||
if *literal <= 1 << 29 {
|
|
||||||
Ok(*literal as u32)
|
|
||||||
} else {
|
|
||||||
Err("larger than 2^29")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err("not a power of two")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err("not an unsuffixed integer")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut literal_error = None;
|
let mut literal_error = None;
|
||||||
if name == sym::align {
|
if name == sym::align {
|
||||||
recognised = true;
|
recognised = true;
|
||||||
@ -966,13 +937,7 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
|||||||
}
|
}
|
||||||
if !recognised {
|
if !recognised {
|
||||||
// Not a word we recognize
|
// Not a word we recognize
|
||||||
struct_span_err!(
|
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
|
||||||
diagnostic,
|
|
||||||
item.span(),
|
|
||||||
E0552,
|
|
||||||
"unrecognized representation hint"
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1080,3 +1045,16 @@ fn allow_unstable<'a>(
|
|||||||
name
|
name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
|
||||||
|
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
|
||||||
|
if literal.is_power_of_two() {
|
||||||
|
// rustc_middle::ty::layout::Align restricts align to <= 2^29
|
||||||
|
if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") }
|
||||||
|
} else {
|
||||||
|
Err("not a power of two")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("not an unsuffixed integer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -280,6 +280,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
|
|||||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
|
||||||
llvm::AddFunctionAttrString(llfn, Function, cstr!("cmse_nonsecure_entry"));
|
llvm::AddFunctionAttrString(llfn, Function, cstr!("cmse_nonsecure_entry"));
|
||||||
}
|
}
|
||||||
|
if let Some(align) = codegen_fn_attrs.alignment {
|
||||||
|
llvm::set_alignment(llfn, align as usize);
|
||||||
|
}
|
||||||
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
|
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
|
||||||
|
|
||||||
// Always annotate functions with the target-cpu they are compiled for.
|
// Always annotate functions with the target-cpu they are compiled for.
|
||||||
|
@ -642,6 +642,9 @@ declare_features! (
|
|||||||
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
|
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
|
||||||
(active, c_unwind, "1.52.0", Some(74990), None),
|
(active, c_unwind, "1.52.0", Some(74990), None),
|
||||||
|
|
||||||
|
/// Allows using `#[repr(align(...))]` on function items
|
||||||
|
(active, fn_align, "1.53.0", Some(82232), None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: actual feature gates
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -38,6 +38,9 @@ pub struct CodegenFnAttrs {
|
|||||||
/// be generated against a specific instruction set. Only usable on architectures which allow
|
/// be generated against a specific instruction set. Only usable on architectures which allow
|
||||||
/// switching between multiple instruction sets.
|
/// switching between multiple instruction sets.
|
||||||
pub instruction_set: Option<InstructionSetAttr>,
|
pub instruction_set: Option<InstructionSetAttr>,
|
||||||
|
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
|
||||||
|
/// aligned to.
|
||||||
|
pub alignment: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -103,6 +106,7 @@ impl CodegenFnAttrs {
|
|||||||
link_section: None,
|
link_section: None,
|
||||||
no_sanitize: SanitizerSet::empty(),
|
no_sanitize: SanitizerSet::empty(),
|
||||||
instruction_set: None,
|
instruction_set: None,
|
||||||
|
alignment: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,17 +1127,41 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
let mut is_transparent = false;
|
let mut is_transparent = false;
|
||||||
|
|
||||||
for hint in &hints {
|
for hint in &hints {
|
||||||
|
if !hint.is_meta_item() {
|
||||||
|
struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
hint.span(),
|
||||||
|
E0565,
|
||||||
|
"meta item in `repr` must be an identifier"
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let (article, allowed_targets) = match hint.name_or_empty() {
|
let (article, allowed_targets) = match hint.name_or_empty() {
|
||||||
_ if !matches!(target, Target::Struct | Target::Enum | Target::Union) => {
|
sym::C => {
|
||||||
("a", "struct, enum, or union")
|
is_c = true;
|
||||||
}
|
|
||||||
name @ sym::C | name @ sym::align => {
|
|
||||||
is_c |= name == sym::C;
|
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Union | Target::Enum => continue,
|
Target::Struct | Target::Union | Target::Enum => continue,
|
||||||
_ => ("a", "struct, enum, or union"),
|
_ => ("a", "struct, enum, or union"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sym::align => {
|
||||||
|
if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) {
|
||||||
|
feature_err(
|
||||||
|
&self.tcx.sess.parse_sess,
|
||||||
|
sym::fn_align,
|
||||||
|
hint.span(),
|
||||||
|
"`repr(align)` attributes on functions are unstable",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
match target {
|
||||||
|
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
|
||||||
|
_ => ("a", "struct, enum, function, or union"),
|
||||||
|
}
|
||||||
|
}
|
||||||
sym::packed => {
|
sym::packed => {
|
||||||
if target != Target::Struct && target != Target::Union {
|
if target != Target::Struct && target != Target::Union {
|
||||||
("a", "struct or union")
|
("a", "struct or union")
|
||||||
@ -1194,7 +1218,17 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => {
|
||||||
|
struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
hint.span(),
|
||||||
|
E0552,
|
||||||
|
"unrecognized representation hint"
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
|
@ -561,6 +561,7 @@ symbols! {
|
|||||||
fmt,
|
fmt,
|
||||||
fmt_internals,
|
fmt_internals,
|
||||||
fmul_fast,
|
fmul_fast,
|
||||||
|
fn_align,
|
||||||
fn_must_use,
|
fn_must_use,
|
||||||
fn_mut,
|
fn_mut,
|
||||||
fn_once,
|
fn_once,
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
//! At present, however, we do run collection across all items in the
|
//! At present, however, we do run collection across all items in the
|
||||||
//! crate as a kind of pass. This should eventually be factored away.
|
//! crate as a kind of pass. This should eventually be factored away.
|
||||||
|
|
||||||
|
// ignore-tidy-filelength
|
||||||
|
|
||||||
use crate::astconv::{AstConv, SizedByDefault};
|
use crate::astconv::{AstConv, SizedByDefault};
|
||||||
use crate::bounds::Bounds;
|
use crate::bounds::Bounds;
|
||||||
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
||||||
@ -2889,6 +2891,36 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if tcx.sess.check_name(attr, sym::repr) {
|
||||||
|
codegen_fn_attrs.alignment = match attr.meta_item_list() {
|
||||||
|
Some(items) => match items.as_slice() {
|
||||||
|
[item] => match item.name_value_literal() {
|
||||||
|
Some((sym::align, literal)) => {
|
||||||
|
let alignment = rustc_attr::parse_alignment(&literal.kind);
|
||||||
|
|
||||||
|
match alignment {
|
||||||
|
Ok(align) => Some(align),
|
||||||
|
Err(msg) => {
|
||||||
|
struct_span_err!(
|
||||||
|
tcx.sess.diagnostic(),
|
||||||
|
attr.span,
|
||||||
|
E0589,
|
||||||
|
"invalid `repr(align)` attribute: {}",
|
||||||
|
msg
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
[] => None,
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
src/test/codegen/align-fn.rs
Normal file
9
src/test/codegen/align-fn.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(fn_align)]
|
||||||
|
|
||||||
|
// CHECK: align 16
|
||||||
|
#[no_mangle]
|
||||||
|
#[repr(align(16))]
|
||||||
|
pub fn fn_align() {}
|
@ -3,7 +3,6 @@
|
|||||||
macro_rules! pass_nonterminal {
|
macro_rules! pass_nonterminal {
|
||||||
($n:expr) => {
|
($n:expr) => {
|
||||||
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
|
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
|
||||||
//~| ERROR unrecognized representation hint
|
|
||||||
struct S;
|
struct S;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,5 @@ LL | pass_nonterminal!(n!());
|
|||||||
|
|
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0552]: unrecognized representation hint
|
error: aborting due to previous error
|
||||||
--> $DIR/nonterminal-expansion.rs:5:16
|
|
||||||
|
|
|
||||||
LL | #[repr(align($n))]
|
|
||||||
| ^^^^^^^^^
|
|
||||||
...
|
|
||||||
LL | pass_nonterminal!(n!());
|
|
||||||
| ------------------------ in this macro invocation
|
|
||||||
|
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0552`.
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// repr currently doesn't support literals
|
// repr currently doesn't support literals
|
||||||
#[repr("C")] //~ ERROR E0565
|
#[repr("C")] //~ ERROR E0565
|
||||||
//~| ERROR E0565
|
struct A {}
|
||||||
struct A { }
|
|
||||||
|
|
||||||
fn main() { }
|
fn main() {}
|
||||||
|
@ -4,12 +4,6 @@ error[E0565]: meta item in `repr` must be an identifier
|
|||||||
LL | #[repr("C")]
|
LL | #[repr("C")]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error[E0565]: meta item in `repr` must be an identifier
|
error: aborting due to previous error
|
||||||
--> $DIR/E0565.rs:2:8
|
|
||||||
|
|
|
||||||
LL | #[repr("C")]
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0565`.
|
For more information about this error, try `rustc --explain E0565`.
|
||||||
|
4
src/test/ui/feature-gates/feature-gate-fn_align.rs
Normal file
4
src/test/ui/feature-gates/feature-gate-fn_align.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
#[repr(align(16))] //~ ERROR `repr(align)` attributes on functions are unstable
|
||||||
|
fn requires_alignment() {}
|
12
src/test/ui/feature-gates/feature-gate-fn_align.stderr
Normal file
12
src/test/ui/feature-gates/feature-gate-fn_align.stderr
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
error[E0658]: `repr(align)` attributes on functions are unstable
|
||||||
|
--> $DIR/feature-gate-fn_align.rs:3:8
|
||||||
|
|
|
||||||
|
LL | #[repr(align(16))]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #82232 <https://github.com/rust-lang/rust/issues/82232> for more information
|
||||||
|
= help: add `#![feature(fn_align)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -13,13 +13,13 @@ fn main() {
|
|||||||
|
|
||||||
#[repr(nothing)]
|
#[repr(nothing)]
|
||||||
let _x = 0;
|
let _x = 0;
|
||||||
//~^^ ERROR attribute should be applied to a struct, enum, or union
|
//~^^ ERROR E0552
|
||||||
|
|
||||||
#[repr(something_not_real)]
|
#[repr(something_not_real)]
|
||||||
loop {
|
loop {
|
||||||
()
|
()
|
||||||
};
|
};
|
||||||
//~^^^^ ERROR attribute should be applied to a struct, enum, or union
|
//~^^^^ ERROR E0552
|
||||||
|
|
||||||
#[repr]
|
#[repr]
|
||||||
let _y = "123";
|
let _y = "123";
|
||||||
|
@ -26,23 +26,17 @@ LL | #[inline(XYZ)]
|
|||||||
LL | let _b = 4;
|
LL | let _b = 4;
|
||||||
| ----------- not a function or closure
|
| ----------- not a function or closure
|
||||||
|
|
||||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
error[E0552]: unrecognized representation hint
|
||||||
--> $DIR/issue-43988.rs:14:12
|
--> $DIR/issue-43988.rs:14:12
|
||||||
|
|
|
|
||||||
LL | #[repr(nothing)]
|
LL | #[repr(nothing)]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
LL | let _x = 0;
|
|
||||||
| ----------- not a struct, enum, or union
|
|
||||||
|
|
||||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
error[E0552]: unrecognized representation hint
|
||||||
--> $DIR/issue-43988.rs:18:12
|
--> $DIR/issue-43988.rs:18:12
|
||||||
|
|
|
|
||||||
LL | #[repr(something_not_real)]
|
LL | #[repr(something_not_real)]
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
LL | / loop {
|
|
||||||
LL | | ()
|
|
||||||
LL | | };
|
|
||||||
| |_____- not a struct, enum, or union
|
|
||||||
|
|
||||||
error[E0518]: attribute should be applied to function or closure
|
error[E0518]: attribute should be applied to function or closure
|
||||||
--> $DIR/issue-43988.rs:30:5
|
--> $DIR/issue-43988.rs:30:5
|
||||||
@ -54,5 +48,5 @@ LL | foo();
|
|||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0517, E0518.
|
Some errors have detailed explanations: E0518, E0552.
|
||||||
For more information about an error, try `rustc --explain E0517`.
|
For more information about an error, try `rustc --explain E0518`.
|
||||||
|
@ -2,7 +2,7 @@ struct Test;
|
|||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
//~^ ERROR attribute should be applied to a struct, enum, or union
|
//~^ ERROR attribute should be applied to an enum
|
||||||
Variant,
|
Variant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
error[E0517]: attribute should be applied to an enum
|
||||||
--> $DIR/repr-disallow-on-variant.rs:4:12
|
--> $DIR/repr-disallow-on-variant.rs:4:12
|
||||||
|
|
|
|
||||||
LL | #[repr(u8)]
|
LL | #[repr(u8)]
|
||||||
| ^^
|
| ^^
|
||||||
LL |
|
LL |
|
||||||
LL | Variant,
|
LL | Variant,
|
||||||
| ------- not a struct, enum, or union
|
| ------- not an enum
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user