diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1d93cbaddd6..2b6841181a7 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -69,9 +69,6 @@ passes_break_non_loop = .suggestion = use `break` on its own without a value inside this `{$kind}` loop .break_expr_suggestion = alternatively, you might have meant to use the available loop label -passes_cannot_inline_naked_function = - naked functions cannot be inlined - passes_cannot_stabilize_deprecated = an API can't be stabilized after it is deprecated .label = invalid version @@ -485,6 +482,11 @@ passes_naked_functions_asm_block = passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} +passes_naked_functions_codegen_attribute = + cannot use additional code generation attributes with `#[naked]` + .label = this attribute is incompatible with `#[naked]` + .label2 = function marked with `#[naked]` here + passes_naked_functions_must_use_noreturn = asm in naked functions must use `noreturn` option .suggestion = consider specifying that the asm block is responsible for returning from the function @@ -492,9 +494,6 @@ passes_naked_functions_must_use_noreturn = passes_naked_functions_operands = only `const` and `sym` operands are supported in naked functions -passes_naked_tracked_caller = - cannot use `#[track_caller]` with `#[naked]` - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce2fa83810f..739847d73d3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -155,7 +155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_std_internal_symbol] => { self.check_rustc_std_internal_symbol(attr, span, target) } - [sym::naked] => self.check_naked(hir_id, attr, span, target), + [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs), [sym::rustc_never_returns_null_ptr] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } @@ -410,12 +410,33 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { + fn check_naked( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + attrs: &[Attribute], + ) -> bool { + const FORBIDDEN: [rustc_span::Symbol; 3] = + [sym::track_caller, sym::inline, sym::target_feature]; + + for other_attr in attrs { + if FORBIDDEN.into_iter().any(|name| other_attr.has_name(name)) { + self.dcx().emit_err(errors::NakedFunctionCodegenAttribute { + span: other_attr.span, + naked_span: attr.span, + }); + + return false; + } + } + match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously + // `#[naked]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { @@ -488,7 +509,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. + /// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid. fn check_track_caller( &self, hir_id: HirId, @@ -498,10 +519,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, ) -> bool { match target { - _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { - self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); - false - } Target::Fn => { // `#[track_caller]` is not valid on weak lang items because they are called via // `extern` declarations and `#[track_caller]` would alter their ABI. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 58d27d5b4bb..03105795bfc 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -79,13 +79,6 @@ pub struct AttrShouldBeAppliedToFn { pub on_crate: bool, } -#[derive(Diagnostic)] -#[diag(passes_naked_tracked_caller, code = E0736)] -pub struct NakedTrackedCaller { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_should_be_applied_to_fn, code = E0739)] pub struct TrackedCallerWrongLocation { @@ -1124,13 +1117,6 @@ pub struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_cannot_inline_naked_function)] -pub struct CannotInlineNakedFunction { - #[primary_span] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_undefined_naked_function_abi)] pub struct UndefinedNakedFunctionAbi; @@ -1196,6 +1182,16 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } +#[derive(Diagnostic)] +#[diag(passes_naked_functions_codegen_attribute, code = E0736)] +pub struct NakedFunctionCodegenAttribute { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_label2)] + pub naked_span: Span, +} + #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d45ee32a624..4040fbd182e 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -14,9 +14,8 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use crate::errors::{ - CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, - UndefinedNakedFunctionAbi, + NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn, + NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi, }; pub(crate) fn provide(providers: &mut Providers) { @@ -53,15 +52,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); - check_inline(tcx, def_id); - } -} - -/// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let attrs = tcx.get_attrs(def_id, sym::inline); - for attr in attrs { - tcx.dcx().emit_err(CannotInlineNakedFunction { span: attr.span }); } } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs new file mode 100644 index 00000000000..9a4f7547518 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.rs @@ -0,0 +1,31 @@ +//@ needs-asm-support +#![feature(naked_functions)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[naked] +pub unsafe extern "C" fn inline_none() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_hint() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(always)] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_always() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(never)] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_never() { + asm!("", options(noreturn)); +} diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr new file mode 100644 index 00000000000..2496e942b17 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -0,0 +1,27 @@ +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:13:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline] + | ^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:20:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:27:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 1619ebfcf39..e6633ddd4f3 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -168,37 +168,6 @@ pub unsafe extern "C" fn inline_none() { } #[naked] -#[inline] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_hint() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline(always)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_always() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline(never)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_never() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline] -//~^ ERROR naked functions cannot be inlined -#[inline(always)] -//~^ ERROR naked functions cannot be inlined -#[inline(never)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_all() { - asm!("", options(noreturn)); -} - #[naked] pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { compile_error!("this is a user specified error") diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 77bc80a101f..736de85765e 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -5,19 +5,19 @@ LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:204:5 + --> $DIR/naked-functions.rs:173:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:210:5 + --> $DIR/naked-functions.rs:179:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:217:10 + --> $DIR/naked-functions.rs:186:10 | LL | asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -249,42 +249,6 @@ warning: Rust ABI is unsupported in naked functions LL | pub unsafe fn rust_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:171:1 - | -LL | #[inline] - | ^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:178:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:185:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:192:1 - | -LL | #[inline] - | ^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:194:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:196:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 33 previous errors; 2 warnings emitted +error: aborting due to 27 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0787`.