Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying alignment for functions #81234

Merged
merged 1 commit into from
Apr 6, 2021
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
50 changes: 14 additions & 36 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
if let Some(items) = attr.meta_item_list() {
sess.mark_attr_used(attr);
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;
if item.is_word() {
let hint = match item.name_or_empty() {
Expand All @@ -890,23 +878,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
acc.push(h);
}
} 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;
if name == sym::align {
recognised = true;
Expand Down Expand Up @@ -966,13 +937,7 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
}
if !recognised {
// Not a word we recognize
struct_span_err!(
diagnostic,
item.span(),
E0552,
"unrecognized representation hint"
)
.emit();
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
}
}
}
Expand Down Expand Up @@ -1080,3 +1045,16 @@ fn allow_unstable<'a>(
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")
}
}
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,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) {
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);

// Always annotate functions with the target-cpu they are compiled for.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,9 @@ declare_features! (
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
(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
// -------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ 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.
pub alignment: Option<u32>,
}

bitflags! {
Expand Down Expand Up @@ -103,6 +106,7 @@ impl CodegenFnAttrs {
link_section: None,
no_sanitize: SanitizerSet::empty(),
instruction_set: None,
alignment: None,
}
}

Expand Down
46 changes: 40 additions & 6 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,17 +1127,41 @@ impl CheckAttrVisitor<'tcx> {
let mut is_transparent = false;

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() {
_ if !matches!(target, Target::Struct | Target::Enum | Target::Union) => {
("a", "struct, enum, or union")
}
name @ sym::C | name @ sym::align => {
is_c |= name == sym::C;
sym::C => {
is_c = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
_ => ("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 => {
if target != Target::Struct && target != Target::Union {
("a", "struct or union")
Expand Down Expand Up @@ -1194,7 +1218,17 @@ impl CheckAttrVisitor<'tcx> {
continue;
}
}
_ => continue,
_ => {
struct_span_err!(
self.tcx.sess,
hint.span(),
E0552,
"unrecognized representation hint"
)
.emit();

continue;
}
};

struct_span_err!(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ symbols! {
fmt,
fmt_internals,
fmul_fast,
fn_align,
fn_must_use,
fn_mut,
fn_once,
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away.

// ignore-tidy-filelength

use crate::astconv::{AstConv, SizedByDefault};
use crate::bounds::Bounds;
use crate::check::intrinsic::intrinsic_operation_unsafety;
Expand Down Expand Up @@ -2884,6 +2886,36 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
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,
};
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/test/codegen/align-fn.rs
Original file line number Diff line number Diff line change
@@ -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() {}
1 change: 0 additions & 1 deletion src/test/ui/attributes/nonterminal-expansion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
macro_rules! pass_nonterminal {
($n:expr) => {
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
//~| ERROR unrecognized representation hint
struct S;
};
}
Expand Down
14 changes: 1 addition & 13 deletions src/test/ui/attributes/nonterminal-expansion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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)

error[E0552]: unrecognized representation hint
--> $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
error: aborting due to previous error

For more information about this error, try `rustc --explain E0552`.
5 changes: 2 additions & 3 deletions src/test/ui/error-codes/E0565.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// repr currently doesn't support literals
#[repr("C")] //~ ERROR E0565
//~| ERROR E0565
struct A { }
struct A {}

fn main() { }
fn main() {}
8 changes: 1 addition & 7 deletions src/test/ui/error-codes/E0565.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ error[E0565]: meta item in `repr` must be an identifier
LL | #[repr("C")]
| ^^^

error[E0565]: meta item in `repr` must be an identifier
--> $DIR/E0565.rs:2:8
|
LL | #[repr("C")]
| ^^^

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0565`.
4 changes: 4 additions & 0 deletions src/test/ui/feature-gates/feature-gate-fn_align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![crate_type = "lib"]

#[repr(align(16))] //~ ERROR `repr(align)` attributes on functions are unstable
fn requires_alignment() {}
12 changes: 12 additions & 0 deletions src/test/ui/feature-gates/feature-gate-fn_align.stderr
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-43988.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ fn main() {

#[repr(nothing)]
Copy link
Contributor

Choose a reason for hiding this comment

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

why did you remove these 2 reprs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

whoops! I think that may have been a leftover of me trying to figure out something, let me try adding them back here.

let _x = 0;
//~^^ ERROR attribute should be applied to a struct, enum, or union
//~^^ ERROR E0552

#[repr(something_not_real)]
loop {
()
};
//~^^^^ ERROR attribute should be applied to a struct, enum, or union
//~^^^^ ERROR E0552

#[repr]
let _y = "123";
Expand Down
18 changes: 6 additions & 12 deletions src/test/ui/issues/issue-43988.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,17 @@ LL | #[inline(XYZ)]
LL | let _b = 4;
| ----------- 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
|
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
|
LL | #[repr(something_not_real)]
| ^^^^^^^^^^^^^^^^^^
LL | / loop {
LL | | ()
LL | | };
| |_____- not a struct, enum, or union
LL | #[repr(something_not_real)]
| ^^^^^^^^^^^^^^^^^^

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

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0517, E0518.
For more information about an error, try `rustc --explain E0517`.
Some errors have detailed explanations: E0518, E0552.
For more information about an error, try `rustc --explain E0518`.
2 changes: 1 addition & 1 deletion src/test/ui/repr/repr-disallow-on-variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ struct Test;

enum Foo {
#[repr(u8)]
//~^ ERROR attribute should be applied to a struct, enum, or union
//~^ ERROR attribute should be applied to an enum
Variant,
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/repr/repr-disallow-on-variant.stderr
Original file line number Diff line number Diff line change
@@ -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
|
LL | #[repr(u8)]
| ^^
LL |
LL | Variant,
| ------- not a struct, enum, or union
| ------- not an enum

error: aborting due to previous error

Expand Down