]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_metadata/src/native_libs.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_metadata / src / native_libs.rs
index 1cbfb0bd5546b4e7416dd5ce2dee05b00fbfa7b1..b855c8e433266470195b6033923ddb784f459185 100644 (file)
@@ -1,26 +1,81 @@
-use rustc_ast::CRATE_NODE_ID;
+use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_hir::def::DefKind;
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
-use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
+use rustc_session::config::CrateType;
+use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
 use rustc_session::parse::feature_err;
+use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
+use crate::errors;
+
+use std::path::PathBuf;
+
+pub fn find_native_static_library(
+    name: &str,
+    verbatim: bool,
+    search_paths: &[PathBuf],
+    sess: &Session,
+) -> PathBuf {
+    let formats = if verbatim {
+        vec![("".into(), "".into())]
+    } else {
+        let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone());
+        // On Windows, static libraries sometimes show up as libfoo.a and other
+        // times show up as foo.lib
+        let unix = ("lib".into(), ".a".into());
+        if os == unix { vec![os] } else { vec![os, unix] }
+    };
+
+    for path in search_paths {
+        for (prefix, suffix) in &formats {
+            let test = path.join(format!("{prefix}{name}{suffix}"));
+            if test.exists() {
+                return test;
+            }
+        }
+    }
+
+    sess.emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
+}
+
+fn find_bundled_library(
+    name: Symbol,
+    verbatim: Option<bool>,
+    kind: NativeLibKind,
+    has_cfg: bool,
+    sess: &Session,
+) -> Option<Symbol> {
+    if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
+        && sess.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
+        && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
+    {
+        let verbatim = verbatim.unwrap_or(false);
+        let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs();
+        return find_native_static_library(name.as_str(), verbatim, search_paths, sess)
+            .file_name()
+            .and_then(|s| s.to_str())
+            .map(Symbol::intern);
+    }
+    None
+}
+
+pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
-    tcx.hir().visit_all_item_likes(&mut collector);
+    for id in tcx.hir().items() {
+        collector.process_item(id);
+    }
     collector.process_command_line();
     collector.libs
 }
 
-crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
+pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
         Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
         None => true,
@@ -32,301 +87,326 @@ struct Collector<'tcx> {
     libs: Vec<NativeLib>,
 }
 
-impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
-    fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
+impl<'tcx> Collector<'tcx> {
+    fn process_item(&mut self, id: rustc_hir::ItemId) {
+        if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
+            return;
+        }
+
+        let it = self.tcx.hir().item(id);
         let hir::ItemKind::ForeignMod { abi, items: foreign_mod_items } = it.kind else {
             return;
         };
 
-        if abi == Abi::Rust || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
+        if matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) {
             return;
         }
 
         // Process all of the #[link(..)]-style arguments
-        let sess = &self.tcx.sess;
+        let sess = self.tcx.sess;
+        let features = self.tcx.features();
+
+        if !sess.opts.unstable_opts.link_directives {
+            return;
+        }
+
         for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
             let Some(items) = m.meta_item_list() else {
                 continue;
             };
-            let mut lib = NativeLib {
-                name: None,
-                kind: NativeLibKind::Unspecified,
-                cfg: None,
-                foreign_module: Some(it.def_id.to_def_id()),
-                wasm_import_module: None,
-                verbatim: None,
-                dll_imports: Vec::new(),
-            };
-            let mut kind_specified = false;
 
+            let mut name = None;
+            let mut kind = None;
+            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() {
-                if item.has_name(sym::kind) {
-                    kind_specified = true;
-                    let Some(kind) = item.value_str() else {
-                        continue; // skip like historical compilers
-                    };
-                    lib.kind = match kind.as_str() {
-                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-                        "static-nobundle" => {
-                            sess.struct_span_warn(
-                                item.span(),
-                                "library kind `static-nobundle` has been superseded by specifying \
-                                modifier `-bundle` with library kind `static`",
-                            )
-                            .emit();
-                            if !self.tcx.features().static_nobundle {
-                                feature_err(
-                                    &self.tcx.sess.parse_sess,
-                                    sym::static_nobundle,
-                                    item.span(),
-                                    "kind=\"static-nobundle\" is unstable",
-                                )
-                                .emit();
-                            }
-                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+                match item.name_or_empty() {
+                    sym::name => {
+                        if name.is_some() {
+                            sess.emit_err(errors::MultipleNamesInLink { span: item.span() });
+                            continue;
                         }
-                        "dylib" => NativeLibKind::Dylib { as_needed: None },
-                        "framework" => NativeLibKind::Framework { as_needed: None },
-                        "raw-dylib" => NativeLibKind::RawDylib,
-                        k => {
-                            struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
-                                .span_label(item.span(), "unknown kind")
-                                .span_label(m.span, "")
-                                .emit();
-                            NativeLibKind::Unspecified
+                        let Some(link_name) = item.value_str() else {
+                            sess.emit_err(errors::LinkNameForm { span: item.span() });
+                            continue;
+                        };
+                        let span = item.name_value_literal_span().unwrap();
+                        if link_name.is_empty() {
+                            sess.emit_err(errors::EmptyLinkName { span });
                         }
-                    };
-                } else if item.has_name(sym::name) {
-                    lib.name = item.value_str();
-                } else if item.has_name(sym::cfg) {
-                    let Some(cfg) = item.meta_item_list() else {
-                        continue; // skip like historical compilers
-                    };
-                    if cfg.is_empty() {
-                        sess.span_err(item.span(), "`cfg()` must have an argument");
-                    } else if let cfg @ Some(..) = cfg[0].meta_item() {
-                        lib.cfg = cfg.cloned();
-                    } else {
-                        sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
+                        name = Some((link_name, span));
                     }
-                } else if item.has_name(sym::wasm_import_module) {
-                    match item.value_str() {
-                        Some(s) => lib.wasm_import_module = Some(s),
-                        None => {
-                            let msg = "must be of the form `#[link(wasm_import_module = \"...\")]`";
-                            sess.span_err(item.span(), msg);
+                    sym::kind => {
+                        if kind.is_some() {
+                            sess.emit_err(errors::MultipleKindsInLink { span: item.span() });
+                            continue;
                         }
-                    }
-                } else {
-                    // currently, like past compilers, ignore unknown
-                    // directives here.
-                }
-            }
-
-            // Do this outside the above loop so we don't depend on modifiers coming
-            // after kinds
-            let mut modifiers_count = 0;
-            for item in items.iter().filter(|item| item.has_name(sym::modifiers)) {
-                if let Some(modifiers) = item.value_str() {
-                    modifiers_count += 1;
-                    let span = item.name_value_literal_span().unwrap();
-                    let mut has_duplicate_modifiers = false;
-                    for modifier in modifiers.as_str().split(',') {
-                        let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
-                            Some(m) => (m, modifier.starts_with('+')),
-                            None => {
-                                // Note: this error also excludes the case with empty modifier
-                                // string, like `modifiers = ""`.
-                                sess.span_err(
-                                    span,
-                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
-                                    before one of: bundle, verbatim, whole-archive, as-needed",
-                                );
-                                continue;
-                            }
+                        let Some(link_kind) = item.value_str() else {
+                            sess.emit_err(errors::LinkKindForm { span: item.span() });
+                            continue;
                         };
 
-                        match (modifier, &mut lib.kind) {
-                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
-                                if bundle.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *bundle = Some(value);
-                            }
-                            ("bundle", _) => {
-                                sess.span_err(
-                                    span,
-                                    "bundle linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("verbatim", _) => {
-                                if lib.verbatim.is_some() {
-                                    has_duplicate_modifiers = true;
+                        let span = item.name_value_literal_span().unwrap();
+                        let link_kind = match link_kind.as_str() {
+                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                            "dylib" => NativeLibKind::Dylib { as_needed: None },
+                            "framework" => {
+                                if !sess.target.is_like_osx {
+                                    sess.emit_err(errors::LinkFrameworkApple { span });
                                 }
-                                lib.verbatim = Some(value);
+                                NativeLibKind::Framework { as_needed: None }
                             }
-
-                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                                if whole_archive.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *whole_archive = Some(value);
-                            }
-                            ("whole-archive", _) => {
-                                sess.span_err(
-                                    span,
-                                    "whole-archive linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("as-needed", NativeLibKind::Dylib { as_needed })
-                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                                if as_needed.is_some() {
-                                    has_duplicate_modifiers = true;
+                            "raw-dylib" => {
+                                if !sess.target.is_like_windows {
+                                    sess.emit_err(errors::FrameworkOnlyWindows { span });
+                                } else if !features.raw_dylib && sess.target.arch == "x86" {
+                                    feature_err(
+                                        &sess.parse_sess,
+                                        sym::raw_dylib,
+                                        span,
+                                        "link kind `raw-dylib` is unstable on x86",
+                                    )
+                                    .emit();
                                 }
-                                *as_needed = Some(value);
+                                NativeLibKind::RawDylib
                             }
-                            ("as-needed", _) => {
-                                sess.span_err(
-                                    span,
-                                    "as-needed linking modifier is only compatible with \
-                                `dylib` and `framework` linking kinds",
-                                );
+                            kind => {
+                                sess.emit_err(errors::UnknownLinkKind { span, kind });
+                                continue;
                             }
+                        };
+                        kind = Some(link_kind);
+                    }
+                    sym::modifiers => {
+                        if modifiers.is_some() {
+                            sess.emit_err(errors::MultipleLinkModifiers { span: item.span() });
+                            continue;
+                        }
+                        let Some(link_modifiers) = item.value_str() else {
+                            sess.emit_err(errors::LinkModifiersForm { span: item.span() });
+                            continue;
+                        };
+                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
+                    }
+                    sym::cfg => {
+                        if cfg.is_some() {
+                            sess.emit_err(errors::MultipleCfgs { span: item.span() });
+                            continue;
+                        }
+                        let Some(link_cfg) = item.meta_item_list() else {
+                            sess.emit_err(errors::LinkCfgForm { span: item.span() });
+                            continue;
+                        };
+                        let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
+                            sess.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
+                            continue;
+                        };
+                        if !features.link_cfg {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::link_cfg,
+                                item.span(),
+                                "link cfg is unstable",
+                            )
+                            .emit();
+                        }
+                        cfg = Some(link_cfg.clone());
+                    }
+                    sym::wasm_import_module => {
+                        if wasm_import_module.is_some() {
+                            sess.emit_err(errors::MultipleWasmImport { span: item.span() });
+                            continue;
+                        }
+                        let Some(link_wasm_import_module) = item.value_str() else {
+                            sess.emit_err(errors::WasmImportForm { span: item.span() });
+                            continue;
+                        };
+                        wasm_import_module = Some((link_wasm_import_module, item.span()));
+                    }
+                    sym::import_name_type => {
+                        if import_name_type.is_some() {
+                            sess.emit_err(errors::MultipleImportNameType { span: item.span() });
+                            continue;
+                        }
+                        let Some(link_import_name_type) = item.value_str() else {
+                            sess.emit_err(errors::ImportNameTypeForm { span: item.span() });
+                            continue;
+                        };
+                        if self.tcx.sess.target.arch != "x86" {
+                            sess.emit_err(errors::ImportNameTypeX86 { span: item.span() });
+                            continue;
+                        }
 
-                            _ => {
-                                sess.span_err(
-                                    span,
-                                    &format!(
-                                        "unrecognized linking modifier `{}`, expected one \
-                                    of: bundle, verbatim, whole-archive, as-needed",
-                                        modifier
-                                    ),
-                                );
+                        let link_import_name_type = match link_import_name_type.as_str() {
+                            "decorated" => PeImportNameType::Decorated,
+                            "noprefix" => PeImportNameType::NoPrefix,
+                            "undecorated" => PeImportNameType::Undecorated,
+                            import_name_type => {
+                                sess.emit_err(errors::UnknownImportNameType {
+                                    span: item.span(),
+                                    import_name_type,
+                                });
+                                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()));
                     }
-                    if has_duplicate_modifiers {
-                        let msg =
-                            "same modifier is used multiple times in a single `modifiers` argument";
-                        sess.span_err(item.span(), msg);
+                    _ => {
+                        sess.emit_err(errors::UnexpectedLinkArg { span: item.span() });
                     }
-                } else {
-                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
-                    sess.span_err(item.span(), msg);
                 }
             }
 
-            if modifiers_count > 1 {
-                let msg = "multiple `modifiers` arguments in a single `#[link]` attribute";
-                sess.span_err(m.span, msg);
-            }
+            // Do this outside the above loop so we don't depend on modifiers coming after kinds
+            let mut verbatim = None;
+            if let Some((modifiers, span)) = modifiers {
+                for modifier in modifiers.as_str().split(',') {
+                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
+                        Some(m) => (m, modifier.starts_with('+')),
+                        None => {
+                            sess.emit_err(errors::InvalidLinkModifier { span });
+                            continue;
+                        }
+                    };
 
-            // In general we require #[link(name = "...")] but we allow
-            // #[link(wasm_import_module = "...")] without the `name`.
-            let requires_name = kind_specified || lib.wasm_import_module.is_none();
-            if lib.name.is_none() && requires_name {
-                struct_span_err!(
-                    sess,
-                    m.span,
-                    E0459,
-                    "`#[link(...)]` specified without \
-                                  `name = \"foo\"`"
-                )
-                .span_label(m.span, "missing `name` argument")
-                .emit();
-            }
+                    macro report_unstable_modifier($feature: ident) {
+                        if !features.$feature {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::$feature,
+                                span,
+                                &format!("linking modifier `{modifier}` is unstable"),
+                            )
+                            .emit();
+                        }
+                    }
+                    let assign_modifier = |dst: &mut Option<bool>| {
+                        if dst.is_some() {
+                            sess.emit_err(errors::MultipleModifiers { span, modifier });
+                        } else {
+                            *dst = Some(value);
+                        }
+                    };
+                    match (modifier, &mut kind) {
+                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
+                            assign_modifier(bundle)
+                        }
+                        ("bundle", _) => {
+                            sess.emit_err(errors::BundleNeedsStatic { span });
+                        }
 
-            if lib.kind == NativeLibKind::RawDylib {
-                lib.dll_imports.extend(
-                    foreign_mod_items
-                        .iter()
-                        .map(|child_item| self.build_dll_import(abi, child_item)),
-                );
-            }
+                        ("verbatim", _) => assign_modifier(&mut verbatim),
 
-            self.register_native_lib(Some(m.span), lib);
-        }
-    }
+                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
+                            assign_modifier(whole_archive)
+                        }
+                        ("whole-archive", _) => {
+                            sess.emit_err(errors::WholeArchiveNeedsStatic { span });
+                        }
 
-    fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
-    fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
-    fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
-}
+                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
+                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
+                            report_unstable_modifier!(native_link_modifiers_as_needed);
+                            assign_modifier(as_needed)
+                        }
+                        ("as-needed", _) => {
+                            sess.emit_err(errors::AsNeededCompatibility { span });
+                        }
 
-impl Collector<'_> {
-    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
-        if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
-            match span {
-                Some(span) => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0454,
-                        "`#[link(name = \"\")]` given with empty name"
-                    )
-                    .span_label(span, "empty name given")
-                    .emit();
-                }
-                None => {
-                    self.tcx.sess.err("empty library name given via `-l`");
+                        _ => {
+                            sess.emit_err(errors::UnknownLinkModifier { span, modifier });
+                        }
+                    }
                 }
             }
-            return;
-        }
-        let is_osx = self.tcx.sess.target.is_like_osx;
-        if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx {
-            let msg = "native frameworks are only available on macOS targets";
-            match span {
-                Some(span) => {
-                    struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit();
-                }
-                None => {
-                    self.tcx.sess.err(msg);
+
+            if let Some((_, span)) = wasm_import_module {
+                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
+                    sess.emit_err(errors::IncompatibleWasmLink { span });
                 }
             }
-        }
-        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::link_cfg,
-                span.unwrap(),
-                "kind=\"link_cfg\" is unstable",
-            )
-            .emit();
-        }
-        // this just unwraps lib.name; we already established that it isn't empty above.
-        if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
-            let Some(span) = span else {
-                bug!("raw-dylib libraries are not supported on the command line");
-            };
 
-            if !self.tcx.sess.target.options.is_like_windows {
-                self.tcx.sess.span_fatal(
-                    span,
-                    "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
-                );
+            if wasm_import_module.is_some() {
+                (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
             }
+            let Some((name, name_span)) = name else {
+                sess.emit_err(errors::LinkRequiresName { span: m.span });
+                continue;
+            };
 
-            if lib_name.as_str().contains('\0') {
-                self.tcx.sess.span_err(span, "library name may not contain NUL characters");
+            // 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) {
+                    sess.emit_err(errors::ImportNameTypeRaw { span });
+                }
             }
 
-            if !self.tcx.features().raw_dylib {
-                feature_err(
-                    &self.tcx.sess.parse_sess,
-                    sym::raw_dylib,
-                    span,
-                    "kind=\"raw-dylib\" is unstable",
-                )
-                .emit();
-            }
-        }
+            let dll_imports = match kind {
+                Some(NativeLibKind::RawDylib) => {
+                    if name.as_str().contains('\0') {
+                        sess.emit_err(errors::RawDylibNoNul { span: name_span });
+                    }
+                    foreign_mod_items
+                        .iter()
+                        .map(|child_item| {
+                            self.build_dll_import(
+                                abi,
+                                import_name_type.map(|(import_name_type, _)| import_name_type),
+                                child_item,
+                            )
+                        })
+                        .collect()
+                }
+                _ => {
+                    for child_item in foreign_mod_items {
+                        if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
+                            && self
+                                .tcx
+                                .codegen_fn_attrs(child_item.id.owner_id)
+                                .link_ordinal
+                                .is_some()
+                        {
+                            let link_ordinal_attr = self
+                                .tcx
+                                .hir()
+                                .attrs(child_item.id.owner_id.into())
+                                .iter()
+                                .find(|a| a.has_name(sym::link_ordinal))
+                                .unwrap();
+                            sess.emit_err(errors::LinkOrdinalRawDylib {
+                                span: link_ordinal_attr.span,
+                            });
+                        }
+                    }
+
+                    Vec::new()
+                }
+            };
 
-        self.libs.push(lib);
+            let kind = kind.unwrap_or(NativeLibKind::Unspecified);
+            let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), sess);
+            self.libs.push(NativeLib {
+                name,
+                filename,
+                kind,
+                cfg,
+                foreign_module: Some(it.owner_id.to_def_id()),
+                verbatim,
+                dll_imports,
+            });
+        }
     }
 
     // Process libs passed on the command line
@@ -334,39 +414,27 @@ impl Collector<'_> {
         // First, check for errors
         let mut renames = FxHashSet::default();
         for lib in &self.tcx.sess.opts.libs {
+            if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
+                // Cannot check this when parsing options because the target is not yet available.
+                self.tcx.sess.emit_err(errors::LibFrameworkApple);
+            }
             if let Some(ref new_name) = lib.new_name {
-                let any_duplicate = self
-                    .libs
-                    .iter()
-                    .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| n.as_str() == lib.name);
+                let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.err(&format!(
-                        "an empty renaming target was specified for library `{}`",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
                 } else if !any_duplicate {
-                    self.tcx.sess.err(&format!(
-                        "renaming of the library `{}` was specified, \
-                                                however this crate contains no `#[link(...)]` \
-                                                attributes referencing this library",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(errors::RenamingNoLink { lib_name: &lib.name });
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.err(&format!(
-                        "multiple renamings were \
-                                                specified for library `{}`",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(errors::MultipleRenamings { lib_name: &lib.name });
                 }
             }
         }
 
         // Update kind and, optionally, the name of all native libraries
-        // (there may be more than one) with the specified name.  If any
+        // (there may be more than one) with the specified name. If any
         // library is mentioned more than once, keep the latest mention
         // of it, so that any possible dependent libraries appear before
-        // it.  (This ensures that the linker is able to see symbols from
+        // it. (This ensures that the linker is able to see symbols from
         // all possible dependent libraries before linking in the library
         // in question.)
         for passed_lib in &self.tcx.sess.opts.libs {
@@ -376,26 +444,28 @@ impl Collector<'_> {
             let mut existing = self
                 .libs
                 .drain_filter(|lib| {
-                    if let Some(lib_name) = lib.name {
-                        if lib_name.as_str() == passed_lib.name {
-                            // FIXME: This whole logic is questionable, whether modifiers are
-                            // involved or not, library reordering and kind overriding without
-                            // explicit `:rename` in particular.
-                            if lib.has_modifiers() || passed_lib.has_modifiers() {
-                                self.tcx.sess.span_err(
-                                    self.tcx.def_span(lib.foreign_module.unwrap()),
-                                    "overriding linking modifiers from command line is not supported"
-                                );
-                            }
-                            if passed_lib.kind != NativeLibKind::Unspecified {
-                                lib.kind = passed_lib.kind;
-                            }
-                            if let Some(new_name) = &passed_lib.new_name {
-                                lib.name = Some(Symbol::intern(new_name));
-                            }
-                            lib.verbatim = passed_lib.verbatim;
-                            return true;
+                    if lib.name.as_str() == passed_lib.name {
+                        // FIXME: This whole logic is questionable, whether modifiers are
+                        // involved or not, library reordering and kind overriding without
+                        // explicit `:rename` in particular.
+                        if lib.has_modifiers() || passed_lib.has_modifiers() {
+                            match lib.foreign_module {
+                                Some(def_id) => self.tcx.sess.emit_err(errors::NoLinkModOverride {
+                                    span: Some(self.tcx.def_span(def_id)),
+                                }),
+                                None => {
+                                    self.tcx.sess.emit_err(errors::NoLinkModOverride { span: None })
+                                }
+                            };
                         }
+                        if passed_lib.kind != NativeLibKind::Unspecified {
+                            lib.kind = passed_lib.kind;
+                        }
+                        if let Some(new_name) = &passed_lib.new_name {
+                            lib.name = Symbol::intern(new_name);
+                        }
+                        lib.verbatim = passed_lib.verbatim;
+                        return true;
                     }
                     false
                 })
@@ -403,16 +473,19 @@ impl Collector<'_> {
             if existing.is_empty() {
                 // Add if not found
                 let new_name: Option<&str> = passed_lib.new_name.as_deref();
-                let lib = NativeLib {
-                    name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
+                let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
+                let sess = self.tcx.sess;
+                let filename =
+                    find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, false, sess);
+                self.libs.push(NativeLib {
+                    name,
+                    filename,
                     kind: passed_lib.kind,
                     cfg: None,
                     foreign_module: None,
-                    wasm_import_module: None,
                     verbatim: passed_lib.verbatim,
                     dll_imports: Vec::new(),
-                };
-                self.register_native_lib(None, lib);
+                });
             } else {
                 // Move all existing libraries with the same name to the
                 // end of the command line.
@@ -424,10 +497,11 @@ impl Collector<'_> {
     fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
         let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
             self.tcx
-                .type_of(item.id.def_id)
+                .type_of(item.id.owner_id)
+                .subst_identity()
                 .fn_sig(self.tcx)
                 .inputs()
-                .map_bound(|slice| self.tcx.mk_type_list(slice.iter())),
+                .map_bound(|slice| self.tcx.mk_type_list(slice)),
         );
 
         argument_types
@@ -445,7 +519,12 @@ impl Collector<'_> {
             .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,
@@ -455,31 +534,33 @@ impl Collector<'_> {
                 Abi::Fastcall { .. } => {
                     DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
                 }
-                // Vectorcall is intentionally not supported at this time.
+                Abi::Vectorcall { .. } => {
+                    DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
+                }
                 _ => {
-                    self.tcx.sess.span_fatal(
-                        item.span,
-                        r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#,
-                    );
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span: item.span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.span_fatal(
-                        item.span,
-                        r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#,
-                    );
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span: item.span });
                 }
             }
         };
 
+        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
+        let import_name_type = codegen_fn_attrs
+            .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,
+            name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name),
+            import_name_type,
             calling_convention,
             span: item.span,
+            is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
         }
     }
 }