about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_passes/Cargo.toml1
-rw-r--r--compiler/rustc_ast_passes/messages.ftl23
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs87
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs22
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
5 files changed, 104 insertions, 31 deletions
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index c738cb2aa2f..1940628b44a 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -18,5 +18,6 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
 thin-vec = "0.2.12"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 9a267501230..6eddce7b590 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,20 +1,25 @@
-ast_passes_abi_custom_coroutine =
-    functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
+ast_passes_abi_cannot_be_coroutine =
+    functions with the {$abi} ABI cannot be `{$coroutine_kind_str}`
     .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
 
-ast_passes_abi_custom_invalid_signature =
-    invalid signature for `extern "custom"` function
-    .note = functions with the `"custom"` ABI cannot have any parameters or return type
-    .suggestion = remove the parameters and return type
-
 ast_passes_abi_custom_safe_foreign_function =
-    foreign functions with the `"custom"` ABI cannot be safe
+    foreign functions with the "custom" ABI cannot be safe
     .suggestion = remove the `safe` keyword from this definition
 
 ast_passes_abi_custom_safe_function =
-    functions with the `"custom"` ABI must be unsafe
+    functions with the "custom" ABI must be unsafe
     .suggestion = add the `unsafe` keyword to this definition
 
+ast_passes_abi_must_not_have_parameters_or_return_type=
+    invalid signature for `extern {$abi}` function
+    .note = functions with the {$abi} ABI cannot have any parameters or return type
+    .suggestion = remove the parameters and return type
+
+ast_passes_abi_must_not_have_return_type=
+    invalid signature for `extern {$abi}` function
+    .note = functions with the "custom" ABI cannot have a return type
+    .help = remove the return type
+
 ast_passes_assoc_const_without_body =
     associated constant in `impl` without body
     .suggestion = provide a definition for the constant
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index b69a91e2f5f..da248251203 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
 use std::str::FromStr;
 
 use itertools::{Either, Itertools};
-use rustc_abi::ExternAbi;
+use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
 use rustc_ast::*;
@@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
 use rustc_span::{Ident, Span, kw, sym};
+use rustc_target::spec::{AbiMap, AbiMapping};
 use thin_vec::thin_vec;
 
 use crate::errors::{self, TildeConstReason};
@@ -365,31 +366,77 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    /// An `extern "custom"` function must be unsafe, and must not have any parameters or return
-    /// type.
-    fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
+    /// Check that the signature of this function does not violate the constraints of its ABI.
+    fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
+        match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {
+            AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
+                match canon_abi {
+                    CanonAbi::C
+                    | CanonAbi::Rust
+                    | CanonAbi::RustCold
+                    | CanonAbi::Arm(_)
+                    | CanonAbi::GpuKernel
+                    | CanonAbi::X86(_) => { /* nothing to check */ }
+
+                    CanonAbi::Custom => {
+                        // An `extern "custom"` function must be unsafe.
+                        self.reject_safe_fn(abi, ctxt, sig);
+
+                        // An `extern "custom"` function cannot be `async` and/or `gen`.
+                        self.reject_coroutine(abi, sig);
+
+                        // An `extern "custom"` function must have type `fn()`.
+                        self.reject_params_or_return(abi, ident, sig);
+                    }
+
+                    CanonAbi::Interrupt(interrupt_kind) => {
+                        // An interrupt handler cannot be `async` and/or `gen`.
+                        self.reject_coroutine(abi, sig);
+
+                        if let InterruptKind::X86 = interrupt_kind {
+                            // "x86-interrupt" is special because it does have arguments.
+                            // FIXME(workingjubilee): properly lint on acceptable input types.
+                            if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
+                                self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
+                                    span: ret_ty.span,
+                                    abi,
+                                });
+                            }
+                        } else {
+                            // An `extern "interrupt"` function must have type `fn()`.
+                            self.reject_params_or_return(abi, ident, sig);
+                        }
+                    }
+                }
+            }
+            AbiMapping::Invalid => { /* ignore */ }
+        }
+    }
+
+    fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) {
         let dcx = self.dcx();
 
-        // An `extern "custom"` function must be unsafe.
         match sig.header.safety {
             Safety::Unsafe(_) => { /* all good */ }
             Safety::Safe(safe_span) => {
-                let safe_span =
-                    self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
+                let source_map = self.sess.psess.source_map();
+                let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span));
                 dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
             }
             Safety::Default => match ctxt {
                 FnCtxt::Foreign => { /* all good */ }
                 FnCtxt::Free | FnCtxt::Assoc(_) => {
-                    self.dcx().emit_err(errors::AbiCustomSafeFunction {
+                    dcx.emit_err(errors::AbiCustomSafeFunction {
                         span: sig.span,
+                        abi,
                         unsafe_span: sig.span.shrink_to_lo(),
                     });
                 }
             },
         }
+    }
 
-        // An `extern "custom"` function cannot be `async` and/or `gen`.
+    fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
         if let Some(coroutine_kind) = sig.header.coroutine_kind {
             let coroutine_kind_span = self
                 .sess
@@ -397,14 +444,16 @@ impl<'a> AstValidator<'a> {
                 .source_map()
                 .span_until_non_whitespace(coroutine_kind.span().to(sig.span));
 
-            self.dcx().emit_err(errors::AbiCustomCoroutine {
+            self.dcx().emit_err(errors::AbiCannotBeCoroutine {
                 span: sig.span,
+                abi,
                 coroutine_kind_span,
                 coroutine_kind_str: coroutine_kind.as_str(),
             });
         }
+    }
 
-        // An `extern "custom"` function must not have any parameters or return type.
+    fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
         let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
         if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
             spans.push(ret_ty.span);
@@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
             let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
             let padding = if header_span.is_empty() { "" } else { " " };
 
-            self.dcx().emit_err(errors::AbiCustomInvalidSignature {
+            self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {
                 spans,
                 symbol: ident.name,
                 suggestion_span,
                 padding,
+                abi,
             });
         }
     }
@@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_foreign_fn_bodyless(*ident, body.as_deref());
                 self.check_foreign_fn_headerless(sig.header);
                 self.check_foreign_item_ascii_only(*ident);
-                if self.extern_mod_abi == Some(ExternAbi::Custom) {
-                    self.check_custom_abi(FnCtxt::Foreign, ident, sig);
-                }
+                self.check_extern_fn_signature(
+                    self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
+                    FnCtxt::Foreign,
+                    ident,
+                    sig,
+                );
             }
             ForeignItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         if let FnKind::Fn(ctxt, _, fun) = fk
             && let Extern::Explicit(str_lit, _) = fun.sig.header.ext
-            && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
+            && let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str())
         {
-            self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
+            self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
         }
 
         self.check_c_variadic_type(fk);
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index c437e62f4d3..d387a4a310e 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,5 +1,6 @@
 //! Errors emitted by ast_passes.
 
+use rustc_abi::ExternAbi;
 use rustc_ast::ParamKindOrd;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
@@ -845,6 +846,7 @@ pub(crate) struct AbiCustomSafeForeignFunction {
 pub(crate) struct AbiCustomSafeFunction {
     #[primary_span]
     pub span: Span,
+    pub abi: ExternAbi,
 
     #[suggestion(
         ast_passes_suggestion,
@@ -856,10 +858,11 @@ pub(crate) struct AbiCustomSafeFunction {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_abi_custom_coroutine)]
-pub(crate) struct AbiCustomCoroutine {
+#[diag(ast_passes_abi_cannot_be_coroutine)]
+pub(crate) struct AbiCannotBeCoroutine {
     #[primary_span]
     pub span: Span,
+    pub abi: ExternAbi,
 
     #[suggestion(
         ast_passes_suggestion,
@@ -872,11 +875,12 @@ pub(crate) struct AbiCustomCoroutine {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_abi_custom_invalid_signature)]
+#[diag(ast_passes_abi_must_not_have_parameters_or_return_type)]
 #[note]
-pub(crate) struct AbiCustomInvalidSignature {
+pub(crate) struct AbiMustNotHaveParametersOrReturnType {
     #[primary_span]
     pub spans: Vec<Span>,
+    pub abi: ExternAbi,
 
     #[suggestion(
         ast_passes_suggestion,
@@ -888,3 +892,13 @@ pub(crate) struct AbiCustomInvalidSignature {
     pub symbol: Symbol,
     pub padding: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_abi_must_not_have_return_type)]
+#[note]
+pub(crate) struct AbiMustNotHaveReturnType {
+    #[primary_span]
+    #[help]
+    pub span: Span,
+    pub abi: ExternAbi,
+}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index bd2252c1bf8..8c43d10b9e4 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,5 +1,5 @@
 hir_analysis_abi_custom_clothed_function =
-    items with the `"custom"` ABI can only be declared externally or defined via naked functions
+    items with the "custom" ABI can only be declared externally or defined via naked functions
     .suggestion = convert this to an `#[unsafe(naked)]` function
 
 hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`