about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs34
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs76
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs12
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs79
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_session/src/cstore.rs33
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/Makefile22
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/driver.rs79
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.c65
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.gnu.def18
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.msvc.def18
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/output.txt12
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr21
-rw-r--r--src/test/ui/linkage-attr/link-attr-validation-early.stderr4
-rw-r--r--src/test/ui/linkage-attr/link-attr-validation-late.stderr4
-rw-r--r--src/test/ui/malformed/malformed-regressions.stderr4
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs10
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr17
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs11
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr17
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs10
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr17
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs18
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr23
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs9
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr17
31 files changed, 614 insertions, 46 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 27039cda253..2e614e5dd88 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -8,10 +8,11 @@ use std::path::{Path, PathBuf};
 use std::ptr;
 use std::str;
 
+use crate::common;
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
-use rustc_session::cstore::{DllCallingConvention, DllImport};
+use rustc_session::cstore::DllImport;
 use rustc_session::Session;
 
 /// Helper for adding many files to an archive.
@@ -111,21 +112,18 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
         };
 
         let target = &sess.target;
-        let mingw_gnu_toolchain = target.vendor == "pc"
-            && target.os == "windows"
-            && target.env == "gnu"
-            && target.abi.is_empty();
+        let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
 
         let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
                 if sess.target.arch == "x86" {
                     (
-                        LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
-                        import.ordinal,
+                        common::i686_decorated_name(import, mingw_gnu_toolchain, false),
+                        import.ordinal(),
                     )
                 } else {
-                    (import.name.to_string(), import.ordinal)
+                    (import.name.to_string(), import.ordinal())
                 }
             })
             .collect();
@@ -159,6 +157,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 }
             };
 
+            // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
+            // able to control the *exact* spelling of each of the symbols that are being imported:
+            // hence we don't want `dlltool` adding leading underscores automatically.
             let dlltool = find_binutils_dlltool(sess);
             let result = std::process::Command::new(dlltool)
                 .args([
@@ -168,6 +169,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                     lib_name,
                     "-l",
                     output_path.to_str().unwrap(),
+                    "--no-leading-underscore",
                 ])
                 .output();
 
@@ -322,22 +324,6 @@ impl<'a> LlvmArchiveBuilder<'a> {
             ret
         }
     }
-
-    fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
-        let name = import.name;
-        let prefix = if mingw { "" } else { "_" };
-
-        match import.calling_convention {
-            DllCallingConvention::C => format!("{}{}", prefix, name),
-            DllCallingConvention::Stdcall(arg_list_size) => {
-                format!("{}{}@{}", prefix, name, arg_list_size)
-            }
-            DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
-            DllCallingConvention::Vectorcall(arg_list_size) => {
-                format!("{}@@{}", name, arg_list_size)
-            }
-        }
-    }
 }
 
 fn string_to_io_error(s: String) -> io::Error {
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 72155d874a2..d55f995b933 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -6,6 +6,7 @@
 
 use crate::abi::FnAbiLlvmExt;
 use crate::attributes;
+use crate::common;
 use crate::context::CodegenCx;
 use crate::llvm;
 use crate::value::Value;
@@ -79,13 +80,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
             llfn
         }
     } else {
-        let llfn = cx.declare_fn(sym, fn_abi);
+        let instance_def_id = instance.def_id();
+        let llfn = if tcx.sess.target.arch == "x86" &&
+            let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
+        {
+            cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi)
+        } else {
+            cx.declare_fn(sym, fn_abi)
+        };
         debug!("get_fn: not casting pointer!");
 
         attributes::from_fn_attrs(cx, llfn, instance);
 
-        let instance_def_id = instance.def_id();
-
         // Apply an appropriate linkage/visibility value to our item that we
         // just declared.
         //
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index fb4da9a5f33..63d3bb40a3f 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -10,12 +10,17 @@ use crate::value::Value;
 use rustc_ast::Mutability;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
+use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
+use rustc_target::spec::Target;
 
 use libc::{c_char, c_uint};
+use std::fmt::Write;
 use tracing::debug;
 
 /*
@@ -357,3 +362,74 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
 fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> {
     unsafe { llvm::LLVMIsAConstantInt(v) }
 }
+
+pub(crate) fn get_dllimport<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    id: DefId,
+    name: &str,
+) -> Option<&'tcx DllImport> {
+    tcx.native_library(id)
+        .map(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
+        .flatten()
+}
+
+pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool {
+    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
+}
+
+pub(crate) fn i686_decorated_name(
+    dll_import: &DllImport,
+    mingw: bool,
+    disable_name_mangling: bool,
+) -> String {
+    let name = dll_import.name.as_str();
+
+    let (add_prefix, add_suffix) = match dll_import.import_name_type {
+        Some(PeImportNameType::NoPrefix) => (false, true),
+        Some(PeImportNameType::Undecorated) => (false, false),
+        _ => (true, true),
+    };
+
+    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
+    let mut decorated_name = String::with_capacity(name.len() + 6);
+
+    if disable_name_mangling {
+        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
+        decorated_name.push('\x01');
+    }
+
+    let prefix = if add_prefix && dll_import.is_fn {
+        match dll_import.calling_convention {
+            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
+            DllCallingConvention::Stdcall(_) => (!mingw
+                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
+            .then_some('_'),
+            DllCallingConvention::Fastcall(_) => Some('@'),
+        }
+    } else if !dll_import.is_fn && !mingw {
+        // For static variables, prefix with '_' on MSVC.
+        Some('_')
+    } else {
+        None
+    };
+    if let Some(prefix) = prefix {
+        decorated_name.push(prefix);
+    }
+
+    decorated_name.push_str(name);
+
+    if add_suffix && dll_import.is_fn {
+        match dll_import.calling_convention {
+            DllCallingConvention::C => {}
+            DllCallingConvention::Stdcall(arg_list_size)
+            | DllCallingConvention::Fastcall(arg_list_size) => {
+                write!(&mut decorated_name, "@{}", arg_list_size).unwrap();
+            }
+            DllCallingConvention::Vectorcall(arg_list_size) => {
+                write!(&mut decorated_name, "@@{}", arg_list_size).unwrap();
+            }
+        }
+    }
+
+    decorated_name
+}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 18467e37082..f41ff325590 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -1,5 +1,5 @@
 use crate::base;
-use crate::common::CodegenCx;
+use crate::common::{self, CodegenCx};
 use crate::debuginfo;
 use crate::llvm::{self, True};
 use crate::llvm_util;
@@ -160,7 +160,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
     attrs: &CodegenFnAttrs,
     ty: Ty<'tcx>,
     sym: &str,
-    span_def_id: DefId,
+    def_id: DefId,
 ) -> &'ll Value {
     let llty = cx.layout_of(ty).llvm_type(cx);
     if let Some(linkage) = attrs.linkage {
@@ -175,7 +175,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             cx.layout_of(mt.ty).llvm_type(cx)
         } else {
             cx.sess().span_fatal(
-                cx.tcx.def_span(span_def_id),
+                cx.tcx.def_span(def_id),
                 "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
             )
         };
@@ -194,7 +194,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             real_name.push_str(sym);
             let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
                 cx.sess().span_fatal(
-                    cx.tcx.def_span(span_def_id),
+                    cx.tcx.def_span(def_id),
                     &format!("symbol `{}` is already defined", &sym),
                 )
             });
@@ -202,6 +202,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             llvm::LLVMSetInitializer(g2, g1);
             g2
         }
+    } else if cx.tcx.sess.target.arch == "x86" &&
+        let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
+    {
+        cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty)
     } else {
         // Generate an external declaration.
         // FIXME(nagisa): investigate whether it can be changed into define_global
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 7d3bedbfe43..d520efed9b8 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -335,7 +335,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ABI, linking, symbols, and FFI
     ungated!(
         link, Normal,
-        template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
+        template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
         DuplicatesOk,
     ),
     ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index c5e39507d7e..8bafe203748 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -5,7 +5,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
-use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
+use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
@@ -61,6 +61,7 @@ impl<'tcx> Collector<'tcx> {
             let mut modifiers = None;
             let mut cfg = None;
             let mut wasm_import_module = None;
+            let mut import_name_type = None;
             for item in items.iter() {
                 match item.name_or_empty() {
                     sym::name => {
@@ -199,9 +200,51 @@ impl<'tcx> Collector<'tcx> {
                         };
                         wasm_import_module = Some((link_wasm_import_module, item.span()));
                     }
+                    sym::import_name_type => {
+                        if import_name_type.is_some() {
+                            let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_import_name_type) = item.value_str() else {
+                            let msg = "import name type must be of the form `import_name_type = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        if self.tcx.sess.target.arch != "x86" {
+                            let msg = "import name type is only supported on x86";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+
+                        let link_import_name_type = match link_import_name_type.as_str() {
+                            "decorated" => PeImportNameType::Decorated,
+                            "noprefix" => PeImportNameType::NoPrefix,
+                            "undecorated" => PeImportNameType::Undecorated,
+                            import_name_type => {
+                                let msg = format!(
+                                    "unknown import name type `{import_name_type}`, expected one of: \
+                                     decorated, noprefix, undecorated"
+                                );
+                                sess.span_err(item.span(), msg);
+                                continue;
+                            }
+                        };
+                        if !features.raw_dylib {
+                            let span = item.name_value_literal_span().unwrap();
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::raw_dylib,
+                                span,
+                                "import name type is unstable",
+                            )
+                            .emit();
+                        }
+                        import_name_type = Some((link_import_name_type, item.span()));
+                    }
                     _ => {
                         let msg = "unexpected `#[link]` argument, expected one of: \
-                                   name, kind, modifiers, cfg, wasm_import_module";
+                                   name, kind, modifiers, cfg, wasm_import_module, import_name_type";
                         sess.span_err(item.span(), msg);
                     }
                 }
@@ -315,6 +358,14 @@ impl<'tcx> Collector<'tcx> {
                 .emit();
             }
 
+            // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
+            if let Some((_, span)) = import_name_type {
+                if kind != Some(NativeLibKind::RawDylib) {
+                    let msg = "import name type can only be used with link kind `raw-dylib`";
+                    sess.span_err(span, msg);
+                }
+            }
+
             let dll_imports = match kind {
                 Some(NativeLibKind::RawDylib) => {
                     if let Some((name, span)) = name && name.as_str().contains('\0') {
@@ -325,7 +376,13 @@ impl<'tcx> Collector<'tcx> {
                     }
                     foreign_mod_items
                         .iter()
-                        .map(|child_item| self.build_dll_import(abi, child_item))
+                        .map(|child_item| {
+                            self.build_dll_import(
+                                abi,
+                                import_name_type.map(|(import_name_type, _)| import_name_type),
+                                child_item,
+                            )
+                        })
                         .collect()
                 }
                 _ => {
@@ -486,7 +543,12 @@ impl<'tcx> Collector<'tcx> {
             .sum()
     }
 
-    fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
+    fn build_dll_import(
+        &self,
+        abi: Abi,
+        import_name_type: Option<PeImportNameType>,
+        item: &hir::ForeignItemRef,
+    ) -> DllImport {
         let calling_convention = if self.tcx.sess.target.arch == "x86" {
             match abi {
                 Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
@@ -518,11 +580,18 @@ impl<'tcx> Collector<'tcx> {
             }
         };
 
+        let import_name_type = self
+            .tcx
+            .codegen_fn_attrs(item.id.def_id)
+            .link_ordinal
+            .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
+
         DllImport {
             name: item.ident.name,
-            ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal,
+            import_name_type,
             calling_convention,
             span: item.span,
+            is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 5bf40f20595..643294cace4 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -341,7 +341,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             assert_eq!(cnum, LOCAL_CRATE);
             false
         },
-        native_library_kind: |tcx, id| {
+        native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind),
+        native_library: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
                 .filter(|lib| native_libs::relevant_lib(&tcx.sess, lib))
@@ -355,7 +356,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         .foreign_items
                         .contains(&id)
                 })
-                .map(|l| l.kind)
         },
         native_libraries: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9bb9d50d1e8..ecedbe8fc8e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1566,6 +1566,9 @@ rustc_queries! {
         -> Option<NativeLibKind> {
         desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
     }
+    query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
+        desc { |tcx| "native_library({})", tcx.def_path_str(def_id) }
+    }
 
     /// Does lifetime resolution, but does not descend into trait items. This
     /// should only be used for resolving lifetimes of on trait definitions,
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index c1fd3c7c61b..11ef75bb2d4 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -81,10 +81,29 @@ impl NativeLib {
     }
 }
 
+/// Different ways that the PE Format can decorate a symbol name.
+/// From <https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-name-type>
+#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq, Eq)]
+pub enum PeImportNameType {
+    /// IMPORT_ORDINAL
+    /// Uses the ordinal (i.e., a number) rather than the name.
+    Ordinal(u16),
+    /// Same as IMPORT_NAME
+    /// Name is decorated with all prefixes and suffixes.
+    Decorated,
+    /// Same as IMPORT_NAME_NOPREFIX
+    /// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept.
+    NoPrefix,
+    /// Same as IMPORT_NAME_UNDECORATE
+    /// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all
+    /// trailing characters) are skipped.
+    Undecorated,
+}
+
 #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct DllImport {
     pub name: Symbol,
-    pub ordinal: Option<u16>,
+    pub import_name_type: Option<PeImportNameType>,
     /// Calling convention for the function.
     ///
     /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any
@@ -92,6 +111,18 @@ pub struct DllImport {
     pub calling_convention: DllCallingConvention,
     /// Span of import's "extern" declaration; used for diagnostics.
     pub span: Span,
+    /// Is this for a function (rather than a static variable).
+    pub is_fn: bool,
+}
+
+impl DllImport {
+    pub fn ordinal(&self) -> Option<u16> {
+        if let Some(PeImportNameType::Ordinal(ordinal)) = self.import_name_type {
+            Some(ordinal)
+        } else {
+            None
+        }
+    }
 }
 
 /// Calling convention for a function defined in an external library.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 5085e3aedfd..ef8b6851e14 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -803,6 +803,7 @@ symbols! {
         impl_trait_in_bindings,
         implied_by,
         import,
+        import_name_type,
         import_shadowing,
         imported_main,
         in_band_lifetimes,
diff --git a/src/test/run-make/raw-dylib-import-name-type/Makefile b/src/test/run-make/raw-dylib-import-name-type/Makefile
new file mode 100644
index 00000000000..fcc60e88e1a
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/Makefile
@@ -0,0 +1,22 @@
+# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
+
+# only-x86
+# only-windows
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+	$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
+ifdef IS_MSVC
+	$(CC) "$(TMPDIR)"/extern.obj extern.msvc.def -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
+else
+	$(CC) "$(TMPDIR)"/extern.obj extern.gnu.def --no-leading-underscore -shared -o "$(TMPDIR)"/extern.dll
+endif
+	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/output.txt output.txt
+else
+	$(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
diff --git a/src/test/run-make/raw-dylib-import-name-type/driver.rs b/src/test/run-make/raw-dylib-import-name-type/driver.rs
new file mode 100644
index 00000000000..74e9a89fbdf
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/driver.rs
@@ -0,0 +1,79 @@
+#![feature(raw_dylib)]
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
+extern "C" {
+    fn cdecl_fn_undecorated(i: i32);
+    static mut extern_variable_undecorated: i32;
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
+extern "C" {
+    fn cdecl_fn_noprefix(i: i32);
+    static mut extern_variable_noprefix: i32;
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
+extern "C" {
+    fn cdecl_fn_decorated(i: i32);
+    static mut extern_variable_decorated: i32;
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
+extern "stdcall" {
+    fn stdcall_fn_undecorated(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
+extern "stdcall" {
+    fn stdcall_fn_noprefix(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
+extern "stdcall" {
+    fn stdcall_fn_decorated(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
+extern "fastcall" {
+    fn fastcall_fn_undecorated(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
+extern "fastcall" {
+    fn fastcall_fn_noprefix(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
+extern "fastcall" {
+    fn fastcall_fn_decorated(i: i32);
+}
+
+#[link(name = "extern", kind = "raw-dylib")]
+extern {
+    fn print_extern_variable_undecorated();
+    fn print_extern_variable_noprefix();
+    fn print_extern_variable_decorated();
+}
+
+pub fn main() {
+    unsafe {
+        cdecl_fn_undecorated(1);
+        cdecl_fn_noprefix(2);
+        cdecl_fn_decorated(3);
+
+        stdcall_fn_undecorated(4);
+        stdcall_fn_noprefix(5);
+        stdcall_fn_decorated(6);
+
+        fastcall_fn_undecorated(7);
+        fastcall_fn_noprefix(8);
+        fastcall_fn_decorated(9);
+
+        extern_variable_undecorated = 42;
+        print_extern_variable_undecorated();
+        extern_variable_noprefix = 43;
+        print_extern_variable_noprefix();
+        extern_variable_decorated = 44;
+        print_extern_variable_decorated();
+    }
+}
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.c b/src/test/run-make/raw-dylib-import-name-type/extern.c
new file mode 100644
index 00000000000..1102158e249
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void _cdecl cdecl_fn_undecorated(int i) {
+    printf("cdecl_fn_undecorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void _cdecl cdecl_fn_noprefix(int i) {
+    printf("cdecl_fn_noprefix(%d)\n", i);
+    fflush(stdout);
+}
+
+void _cdecl cdecl_fn_decorated(int i) {
+    printf("cdecl_fn_decorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void __stdcall stdcall_fn_undecorated(int i) {
+    printf("stdcall_fn_undecorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void __stdcall stdcall_fn_noprefix(int i) {
+    printf("stdcall_fn_noprefix(%d)\n", i);
+    fflush(stdout);
+}
+
+void __stdcall stdcall_fn_decorated(int i) {
+    printf("stdcall_fn_decorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void __fastcall fastcall_fn_undecorated(int i) {
+    printf("fastcall_fn_undecorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void __fastcall fastcall_fn_noprefix(int i) {
+    printf("fastcall_fn_noprefix(%d)\n", i);
+    fflush(stdout);
+}
+
+void __fastcall fastcall_fn_decorated(int i) {
+    printf("fastcall_fn_decorated(%d)\n", i);
+    fflush(stdout);
+}
+
+int extern_variable_undecorated = 0;
+__declspec(dllexport) void print_extern_variable_undecorated() {
+    printf("extern_variable_undecorated value: %d\n", extern_variable_undecorated);
+    fflush(stdout);
+}
+
+int extern_variable_noprefix = 0;
+__declspec(dllexport) void print_extern_variable_noprefix() {
+    printf("extern_variable_noprefix value: %d\n", extern_variable_noprefix);
+    fflush(stdout);
+}
+
+int extern_variable_decorated = 0;
+__declspec(dllexport) void print_extern_variable_decorated() {
+    printf("extern_variable_decorated value: %d\n", extern_variable_decorated);
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def b/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
new file mode 100644
index 00000000000..f06ce67e030
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
@@ -0,0 +1,18 @@
+LIBRARY extern
+EXPORTS
+    cdecl_fn_undecorated
+    cdecl_fn_noprefix
+    cdecl_fn_decorated
+    stdcall_fn_undecorated
+    stdcall_fn_noprefix@4
+    fastcall_fn_undecorated
+    @fastcall_fn_decorated@4
+
+    ;ld doesn't handle fully-decorated stdcall, or no-prefix fastcall
+    _stdcall_fn_decorated@4=stdcall_fn_decorated@4
+    fastcall_fn_noprefix@4=@fastcall_fn_noprefix@4
+
+    ;Variables are never decorated
+    extern_variable_undecorated
+    extern_variable_noprefix
+    extern_variable_decorated
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def b/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
new file mode 100644
index 00000000000..9dc333707cb
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
@@ -0,0 +1,18 @@
+LIBRARY extern
+EXPORTS
+    cdecl_fn_undecorated
+    cdecl_fn_noprefix
+    cdecl_fn_decorated
+    stdcall_fn_undecorated
+    _stdcall_fn_decorated@4
+    fastcall_fn_undecorated
+    @fastcall_fn_decorated@4
+
+    ;MSVC doesn't seem to recognize the "no prefix" syntax.
+    stdcall_fn_noprefix@4=_stdcall_fn_noprefix@4
+    fastcall_fn_noprefix@4=@fastcall_fn_noprefix@4
+
+    ;Variables are never decorated
+    extern_variable_undecorated
+    extern_variable_noprefix
+    extern_variable_decorated
diff --git a/src/test/run-make/raw-dylib-import-name-type/output.txt b/src/test/run-make/raw-dylib-import-name-type/output.txt
new file mode 100644
index 00000000000..855b20a8645
--- /dev/null
+++ b/src/test/run-make/raw-dylib-import-name-type/output.txt
@@ -0,0 +1,12 @@
+cdecl_fn_undecorated(1)
+cdecl_fn_noprefix(2)
+cdecl_fn_decorated(3)
+stdcall_fn_undecorated(4)
+stdcall_fn_noprefix(5)
+stdcall_fn_decorated(6)
+fastcall_fn_undecorated(7)
+fastcall_fn_noprefix(8)
+fastcall_fn_decorated(9)
+extern_variable_undecorated value: 42
+extern_variable_noprefix value: 43
+extern_variable_decorated value: 44
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
new file mode 100644
index 00000000000..33655cf8bdc
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
@@ -0,0 +1,8 @@
+// only-windows
+// only-x86
+#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
+//~^ ERROR link kind `raw-dylib` is unstable
+//~| ERROR import name type is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
new file mode 100644
index 00000000000..be82dd11926
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
@@ -0,0 +1,21 @@
+error[E0658]: link kind `raw-dylib` is unstable
+  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
+   |                             ^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error[E0658]: import name type is unstable
+  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
+   |                                                             ^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/linkage-attr/link-attr-validation-early.stderr b/src/test/ui/linkage-attr/link-attr-validation-early.stderr
index d36601ed0b4..903141e439d 100644
--- a/src/test/ui/linkage-attr/link-attr-validation-early.stderr
+++ b/src/test/ui/linkage-attr/link-attr-validation-early.stderr
@@ -1,4 +1,4 @@
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:2:1
    |
 LL | #[link]
@@ -8,7 +8,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:4:1
    |
 LL | #[link = "foo"]
diff --git a/src/test/ui/linkage-attr/link-attr-validation-late.stderr b/src/test/ui/linkage-attr/link-attr-validation-late.stderr
index bb08f9a4c02..dd0f1dba2ec 100644
--- a/src/test/ui/linkage-attr/link-attr-validation-late.stderr
+++ b/src/test/ui/linkage-attr/link-attr-validation-late.stderr
@@ -1,10 +1,10 @@
-error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
   --> $DIR/link-attr-validation-late.rs:5:22
    |
 LL | #[link(name = "...", "literal")]
    |                      ^^^^^^^^^
 
-error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
   --> $DIR/link-attr-validation-late.rs:6:22
    |
 LL | #[link(name = "...", unknown)]
diff --git a/src/test/ui/malformed/malformed-regressions.stderr b/src/test/ui/malformed/malformed-regressions.stderr
index 13c12ff7213..8c2625bdf0d 100644
--- a/src/test/ui/malformed/malformed-regressions.stderr
+++ b/src/test/ui/malformed/malformed-regressions.stderr
@@ -26,7 +26,7 @@ LL | #[inline = ""]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:7:1
    |
 LL | #[link]
@@ -35,7 +35,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:9:1
    |
 LL | #[link = ""]
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
new file mode 100644
index 00000000000..9e739c02dc8
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
@@ -0,0 +1,10 @@
+// only-windows
+// only-x86
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
+//~^ ERROR import name type must be of the form `import_name_type = "string"`
+extern "C" { }
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
new file mode 100644
index 00000000000..ee10b0114a4
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/import-name-type-invalid-format.rs:3:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: import name type must be of the form `import_name_type = "string"`
+  --> $DIR/import-name-type-invalid-format.rs:6:42
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
+   |                                          ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs b/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
new file mode 100644
index 00000000000..c404dbae468
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
@@ -0,0 +1,11 @@
+// ignore-tidy-linelength
+// only-windows
+// only-x86
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
+//~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
+extern "C" { }
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
new file mode 100644
index 00000000000..936c8aa7359
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/import-name-type-multiple.rs:4:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: multiple `import_name_type` arguments in a single `#[link]` attribute
+  --> $DIR/import-name-type-multiple.rs:7:74
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
+   |                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
new file mode 100644
index 00000000000..350b0294641
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
@@ -0,0 +1,10 @@
+// only-windows
+// only-x86
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
+//~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
+extern "C" { }
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
new file mode 100644
index 00000000000..b6871a0d317
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/import-name-type-unknown-value.rs:3:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
+  --> $DIR/import-name-type-unknown-value.rs:6:42
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
new file mode 100644
index 00000000000..b467917bacc
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
@@ -0,0 +1,18 @@
+// only-windows
+// only-x86
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo", import_name_type = "decorated")]
+//~^ ERROR import name type can only be used with link kind `raw-dylib`
+extern "C" { }
+
+#[link(name = "bar", kind = "static", import_name_type = "decorated")]
+//~^ ERROR import name type can only be used with link kind `raw-dylib`
+extern "C" { }
+
+// Specifying `import_name_type` before `kind` shouldn't raise an error.
+#[link(name = "bar", import_name_type = "decorated", kind = "raw-dylib")]
+extern "C" { }
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
new file mode 100644
index 00000000000..c35333fb88d
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
@@ -0,0 +1,23 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/import-name-type-unsupported-link-kind.rs:3:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: import name type can only be used with link kind `raw-dylib`
+  --> $DIR/import-name-type-unsupported-link-kind.rs:6:22
+   |
+LL | #[link(name = "foo", import_name_type = "decorated")]
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: import name type can only be used with link kind `raw-dylib`
+  --> $DIR/import-name-type-unsupported-link-kind.rs:10:39
+   |
+LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs b/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs
new file mode 100644
index 00000000000..4e6de7d6ac3
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs
@@ -0,0 +1,9 @@
+// only-windows
+// ignore-x86
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
+//~^ ERROR import name type is only supported on x86
+extern "C" { }
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr b/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr
new file mode 100644
index 00000000000..d8a585145a7
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/import-name-type-x86-only.rs:3:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: import name type is only supported on x86
+  --> $DIR/import-name-type-x86-only.rs:5:42
+   |
+LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+