summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-04-06 04:35:26 +0000
committerbors <bors@rust-lang.org>2021-04-06 04:35:26 +0000
commita6e7a5aa5dc842ddb64607040aefb6ec33e22b59 (patch)
tree5e5cecc462513a6cd3798a8b5b030084dca4d0df
parent0c7d4effd71f826abb9651419c316b9b57b8ac97 (diff)
parent448d07683a6defd567996114793a09c9a8aef5df (diff)
downloadrust-a6e7a5aa5dc842ddb64607040aefb6ec33e22b59.tar.gz
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`.
-rw-r--r--compiler/rustc_attr/src/builtin.rs50
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs46
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/collect.rs32
-rw-r--r--src/test/codegen/align-fn.rs9
-rw-r--r--src/test/ui/attributes/nonterminal-expansion.rs1
-rw-r--r--src/test/ui/attributes/nonterminal-expansion.stderr14
-rw-r--r--src/test/ui/error-codes/E0565.rs5
-rw-r--r--src/test/ui/error-codes/E0565.stderr8
-rw-r--r--src/test/ui/feature-gates/feature-gate-fn_align.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-fn_align.stderr12
-rw-r--r--src/test/ui/issues/issue-43988.rs4
-rw-r--r--src/test/ui/issues/issue-43988.stderr18
-rw-r--r--src/test/ui/repr/repr-disallow-on-variant.rs2
-rw-r--r--src/test/ui/repr/repr-disallow-on-variant.stderr4
18 files changed, 137 insertions, 83 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index e58b266fdb9..20971ebb957 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -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() {
@@ -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;
@@ -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");
}
}
}
@@ -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")
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index af895ccc036..e06c1c825f6 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -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) {
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.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index abbeb9554e3..93de4891ec7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -642,6 +642,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
// -------------------------------------------------------------------------
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index bfca6a5f574..7024d9a3d21 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -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! {
@@ -103,6 +106,7 @@ impl CodegenFnAttrs {
link_section: None,
no_sanitize: SanitizerSet::empty(),
instruction_set: None,
+ alignment: None,
}
}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d1a3971f569..df292b14176 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -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")
@@ -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!(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e4810fe7059..54fea551594 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -561,6 +561,7 @@ symbols! {
fmt,
fmt_internals,
fmul_fast,
+ fn_align,
fn_must_use,
fn_mut,
fn_once,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 53dc79106de..1477418d5d8 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -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;
@@ -2889,6 +2891,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,
+ };
}
}
diff --git a/src/test/codegen/align-fn.rs b/src/test/codegen/align-fn.rs
new file mode 100644
index 00000000000..c5886cf2808
--- /dev/null
+++ b/src/test/codegen/align-fn.rs
@@ -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() {}
diff --git a/src/test/ui/attributes/nonterminal-expansion.rs b/src/test/ui/attributes/nonterminal-expansion.rs
index b4f523936a0..d663431d683 100644
--- a/src/test/ui/attributes/nonterminal-expansion.rs
+++ b/src/test/ui/attributes/nonterminal-expansion.rs
@@ -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;
};
}
diff --git a/src/test/ui/attributes/nonterminal-expansion.stderr b/src/test/ui/attributes/nonterminal-expansion.stderr
index 9f7f185f947..75663a666a5 100644
--- a/src/test/ui/attributes/nonterminal-expansion.stderr
+++ b/src/test/ui/attributes/nonterminal-expansion.stderr
@@ -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`.
diff --git a/src/test/ui/error-codes/E0565.rs b/src/test/ui/error-codes/E0565.rs
index 3bf42867610..df76f6b13af 100644
--- a/src/test/ui/error-codes/E0565.rs
+++ b/src/test/ui/error-codes/E0565.rs
@@ -1,6 +1,5 @@
// repr currently doesn't support literals
#[repr("C")] //~ ERROR E0565
- //~| ERROR E0565
-struct A { }
+struct A {}
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/error-codes/E0565.stderr b/src/test/ui/error-codes/E0565.stderr
index aa0951528e1..6ed90c0ae4f 100644
--- a/src/test/ui/error-codes/E0565.stderr
+++ b/src/test/ui/error-codes/E0565.stderr
@@ -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`.
diff --git a/src/test/ui/feature-gates/feature-gate-fn_align.rs b/src/test/ui/feature-gates/feature-gate-fn_align.rs
new file mode 100644
index 00000000000..ea873dba269
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-fn_align.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+
+#[repr(align(16))] //~ ERROR `repr(align)` attributes on functions are unstable
+fn requires_alignment() {}
diff --git a/src/test/ui/feature-gates/feature-gate-fn_align.stderr b/src/test/ui/feature-gates/feature-gate-fn_align.stderr
new file mode 100644
index 00000000000..5ff124e48dc
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-fn_align.stderr
@@ -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`.
diff --git a/src/test/ui/issues/issue-43988.rs b/src/test/ui/issues/issue-43988.rs
index 4b3a0269bae..b114e8e0333 100644
--- a/src/test/ui/issues/issue-43988.rs
+++ b/src/test/ui/issues/issue-43988.rs
@@ -13,13 +13,13 @@ fn main() {
#[repr(nothing)]
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";
diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr
index f1205d447e4..03aa37f5207 100644
--- a/src/test/ui/issues/issue-43988.stderr
+++ b/src/test/ui/issues/issue-43988.stderr
@@ -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
@@ -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`.
diff --git a/src/test/ui/repr/repr-disallow-on-variant.rs b/src/test/ui/repr/repr-disallow-on-variant.rs
index 90cad7e647b..d9bd0b0e38a 100644
--- a/src/test/ui/repr/repr-disallow-on-variant.rs
+++ b/src/test/ui/repr/repr-disallow-on-variant.rs
@@ -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,
}
diff --git a/src/test/ui/repr/repr-disallow-on-variant.stderr b/src/test/ui/repr/repr-disallow-on-variant.stderr
index 70b45e393fc..f7e4dcc9d81 100644
--- a/src/test/ui/repr/repr-disallow-on-variant.stderr
+++ b/src/test/ui/repr/repr-disallow-on-variant.stderr
@@ -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