diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index dfc726efeb998..d8da18cab9c08 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -4,6 +4,11 @@ -passes_see_issue = see issue #{$issue} for more information +-fn_align_hint = + `#[repr(align(...))]` is valid on functions +-fn_align_hint_align_present = + `#[repr(align(...))]` alone is valid on functions + passes_abi_invalid_attribute = `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions passes_abi_ne = @@ -24,22 +29,32 @@ passes_allow_internal_unstable = passes_attr_application_enum = attribute should be applied to an enum .label = not an enum + .align_note = {-fn_align_hint} + .align_note_present = {-fn_align_hint_align_present} passes_attr_application_struct = attribute should be applied to a struct .label = not a struct + .align_note = {-fn_align_hint} + .align_note_present = {-fn_align_hint_align_present} passes_attr_application_struct_enum_function_method_union = attribute should be applied to a struct, enum, function, associated function, or union .label = not a struct, enum, function, associated function, or union + .align_note = {-fn_align_hint} + .align_note_present = {-fn_align_hint_align_present} passes_attr_application_struct_enum_union = attribute should be applied to a struct, enum, or union .label = not a struct, enum, or union + .align_note = {-fn_align_hint} + .align_note_present = {-fn_align_hint_align_present} passes_attr_application_struct_union = attribute should be applied to a struct or union .label = not a struct or union + .align_note = {-fn_align_hint} + .align_note_present = {-fn_align_hint_align_present} passes_attr_crate_level = this attribute can only be applied at the crate level diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index be2b01309c59e..70cd5a5ae70c8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1783,6 +1783,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_simd = false; let mut is_transparent = false; + let has_align = + hints.iter().find_map(|i| (i.name_or_empty() == sym::align).then(|| i.span())); + let (align_note, align_present_note) = + match (self.tcx.features().fn_align, has_align, target) { + // fn_align is on, there's an align attribute, and the target is an fn + (true, Some(span), Target::Fn) => (false, Some(span)), + // fn_align is on, there's no align attribute, and the target is an fn + (true, None, Target::Fn) => (true, None), + _ => (false, None), + }; + for hint in &hints { if !hint.is_meta_item() { self.dcx().emit_err(errors::ReprIdent { span: hint.span() }); @@ -1801,6 +1812,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { hint_span: hint.span(), span, + align_note, + align_present_note, }); } } @@ -1829,6 +1842,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::AttrApplication::StructEnumFunctionMethodUnion { hint_span: hint.span(), span, + align_note, + align_present_note, }, ); } @@ -1839,6 +1854,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::AttrApplication::StructUnion { hint_span: hint.span(), span, + align_note, + align_present_note, }); } else { continue; @@ -1850,6 +1867,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::AttrApplication::Struct { hint_span: hint.span(), span, + align_note, + align_present_note, }); } else { continue; @@ -1863,6 +1882,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { hint_span: hint.span(), span, + align_note, + align_present_note, }); } } @@ -1884,6 +1905,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::AttrApplication::Enum { hint_span: hint.span(), span, + align_note, + align_present_note, }); } else { continue; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 1190e60f41f18..3a0768f7946ea 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1425,6 +1425,11 @@ pub enum AttrApplication { hint_span: Span, #[label] span: Span, + + #[note(passes_align_note)] + align_note: bool, + #[note(passes_align_note_present)] + align_present_note: Option, }, #[diag(passes_attr_application_struct, code = E0517)] Struct { @@ -1432,6 +1437,11 @@ pub enum AttrApplication { hint_span: Span, #[label] span: Span, + + #[note(passes_align_note)] + align_note: bool, + #[note(passes_align_note_present)] + align_present_note: Option, }, #[diag(passes_attr_application_struct_union, code = E0517)] StructUnion { @@ -1439,6 +1449,11 @@ pub enum AttrApplication { hint_span: Span, #[label] span: Span, + + #[note(passes_align_note)] + align_note: bool, + #[note(passes_align_note_present)] + align_present_note: Option, }, #[diag(passes_attr_application_struct_enum_union, code = E0517)] StructEnumUnion { @@ -1446,6 +1461,11 @@ pub enum AttrApplication { hint_span: Span, #[label] span: Span, + + #[note(passes_align_note)] + align_note: bool, + #[note(passes_align_note_present)] + align_present_note: Option, }, #[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)] StructEnumFunctionMethodUnion { @@ -1453,6 +1473,11 @@ pub enum AttrApplication { hint_span: Span, #[label] span: Span, + + #[note(passes_align_note)] + align_note: bool, + #[note(passes_align_note_present)] + align_present_note: Option, }, } diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs new file mode 100644 index 0000000000000..8747f73872862 --- /dev/null +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -0,0 +1,54 @@ +//@ needs-asm-support +#![feature(naked_functions)] +#![feature(fn_align)] +#![crate_type = "lib"] +use std::arch::asm; + +#[repr(C)] +//~^ ERROR attribute should be applied to a struct, enum, or union [E0517] +//~| NOTE `#[repr(align(...))]` is valid on functions +#[naked] +extern "C" fn example1() { + //~^ NOTE not a struct, enum, or union + unsafe { asm!("", options(noreturn)) } +} + +#[repr(transparent)] +//~^ ERROR attribute should be applied to a struct, enum, or union [E0517] +//~| NOTE `#[repr(align(...))]` is valid on functions +#[naked] +extern "C" fn example2() { + //~^ NOTE not a struct, enum, or union + unsafe { asm!("", options(noreturn)) } +} + +#[repr(align(16), C)] +//~^ ERROR attribute should be applied to a struct, enum, or union [E0517] +//~| NOTE `#[repr(align(...))]` alone is valid on functions +#[naked] +extern "C" fn example3() { + //~^ NOTE not a struct, enum, or union + unsafe { asm!("", options(noreturn)) } +} + +// note: two errors because of packed and C +#[repr(C, packed)] +//~^ ERROR attribute should be applied to a struct or union [E0517] +//~| ERROR attribute should be applied to a struct, enum, or union [E0517] +//~| NOTE `#[repr(align(...))]` is valid on functions +//~| NOTE `#[repr(align(...))]` is valid on functions +#[naked] +extern "C" fn example4() { + //~^ NOTE not a struct, enum, or union + //~| NOTE not a struct or union + unsafe { asm!("", options(noreturn)) } +} + +#[repr(u8)] +//~^ ERROR attribute should be applied to an enum [E0517] +//~| NOTE `#[repr(align(...))]` is valid on functions +#[naked] +extern "C" fn example5() { + //~^ NOTE not an enum + unsafe { asm!("", options(noreturn)) } +}