diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_attr/src/builtin.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/attributes.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/active.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/collect.rs | 32 |
7 files changed, 97 insertions, 42 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, + }; } } |
