about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert <folkert@folkertdev.nl>2024-07-16 23:03:13 +0200
committerFolkert <folkert@folkertdev.nl>2024-07-16 23:03:13 +0200
commit4bd36324b6a19afdbcb53de1d41e65b0060a6dbb (patch)
tree5fb3e550eeadb93eafe82f7785551edb69417233
parentceec6ddf9e2d4a41828fce4587180029588ae8eb (diff)
downloadrust-4bd36324b6a19afdbcb53de1d41e65b0060a6dbb.tar.gz
rust-4bd36324b6a19afdbcb53de1d41e65b0060a6dbb.zip
improve error message when `#[naked]` is used with `#[inline]`
-rw-r--r--compiler/rustc_passes/messages.ftl11
-rw-r--r--compiler/rustc_passes/src/check_attr.rs33
-rw-r--r--compiler/rustc_passes/src/errors.rs24
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs14
-rw-r--r--tests/ui/asm/naked-functions-inline.rs31
-rw-r--r--tests/ui/asm/naked-functions-inline.stderr27
-rw-r--r--tests/ui/asm/naked-functions.rs31
-rw-r--r--tests/ui/asm/naked-functions.stderr44
8 files changed, 104 insertions, 111 deletions
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
@@ -80,13 +80,6 @@ pub struct AttrShouldBeAppliedToFn {
 }
 
 #[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 {
     #[primary_span]
@@ -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;
@@ -1197,6 +1183,16 @@ pub struct NakedFunctionsMustUseNoreturn {
 }
 
 #[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 {
     #[primary_span]
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`.