rustc_metadata/
native_libs.rs

1use std::ops::ControlFlow;
2use std::path::{Path, PathBuf};
3
4use rustc_abi::ExternAbi;
5use rustc_ast::CRATE_NODE_ID;
6use rustc_attr_parsing as attr;
7use rustc_data_structures::fx::FxHashSet;
8use rustc_middle::query::LocalCrate;
9use rustc_middle::ty::{self, List, Ty, TyCtxt};
10use rustc_session::Session;
11use rustc_session::config::CrateType;
12use rustc_session::cstore::{
13    DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
14};
15use rustc_session::parse::feature_err;
16use rustc_session::search_paths::PathKind;
17use rustc_session::utils::NativeLibKind;
18use rustc_span::def_id::{DefId, LOCAL_CRATE};
19use rustc_span::{Symbol, sym};
20use rustc_target::spec::LinkSelfContainedComponents;
21
22use crate::{errors, fluent_generated};
23
24pub fn walk_native_lib_search_dirs<R>(
25    sess: &Session,
26    self_contained_components: LinkSelfContainedComponents,
27    apple_sdk_root: Option<&Path>,
28    mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
29) -> ControlFlow<R> {
30    // Library search paths explicitly supplied by user (`-L` on the command line).
31    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Native) {
32        f(&search_path.dir, false)?;
33    }
34    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Framework) {
35        // Frameworks are looked up strictly in framework-specific paths.
36        if search_path.kind != PathKind::All {
37            f(&search_path.dir, true)?;
38        }
39    }
40
41    // The toolchain ships some native library components and self-contained linking was enabled.
42    // Add the self-contained library directory to search paths.
43    if self_contained_components.intersects(
44        LinkSelfContainedComponents::LIBC
45            | LinkSelfContainedComponents::UNWIND
46            | LinkSelfContainedComponents::MINGW,
47    ) {
48        f(&sess.target_tlib_path.dir.join("self-contained"), false)?;
49    }
50
51    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
52    // library directory instead of the self-contained directories.
53    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
54    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
55    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
56    // and sanitizers to self-contained directory, and stop adding this search path.
57    // FIXME: On AIX this also has the side-effect of making the list of library search paths
58    // non-empty, which is needed or the linker may decide to record the LIBPATH env, if
59    // defined, as the search path instead of appending the default search paths.
60    if sess.target.vendor == "fortanix"
61        || sess.target.os == "linux"
62        || sess.target.os == "fuchsia"
63        || sess.target.is_like_aix
64        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
65    {
66        f(&sess.target_tlib_path.dir, false)?;
67    }
68
69    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
70    // we must have the support library stubs in the library search path (#121430).
71    if let Some(sdk_root) = apple_sdk_root
72        && sess.target.llvm_target.contains("macabi")
73    {
74        f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
75        f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
76    }
77
78    ControlFlow::Continue(())
79}
80
81pub fn try_find_native_static_library(
82    sess: &Session,
83    name: &str,
84    verbatim: bool,
85) -> Option<PathBuf> {
86    let formats = if verbatim {
87        vec![("".into(), "".into())]
88    } else {
89        let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone());
90        // On Windows, static libraries sometimes show up as libfoo.a and other
91        // times show up as foo.lib
92        let unix = ("lib".into(), ".a".into());
93        if os == unix { vec![os] } else { vec![os, unix] }
94    };
95
96    // FIXME: Account for self-contained linking settings and Apple SDK.
97    walk_native_lib_search_dirs(
98        sess,
99        LinkSelfContainedComponents::empty(),
100        None,
101        |dir, is_framework| {
102            if !is_framework {
103                for (prefix, suffix) in &formats {
104                    let test = dir.join(format!("{prefix}{name}{suffix}"));
105                    if test.exists() {
106                        return ControlFlow::Break(test);
107                    }
108                }
109            }
110            ControlFlow::Continue(())
111        },
112    )
113    .break_value()
114}
115
116pub fn try_find_native_dynamic_library(
117    sess: &Session,
118    name: &str,
119    verbatim: bool,
120) -> Option<PathBuf> {
121    let formats = if verbatim {
122        vec![("".into(), "".into())]
123    } else {
124        // While the official naming convention for MSVC import libraries
125        // is foo.lib...
126        let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone());
127        // ... Meson follows the libfoo.dll.a convention to
128        // disambiguate .a for static libraries
129        let meson = ("lib".into(), ".dll.a".into());
130        // and MinGW uses .a altogether
131        let mingw = ("lib".into(), ".a".into());
132        vec![os, meson, mingw]
133    };
134
135    walk_native_lib_search_dirs(
136        sess,
137        LinkSelfContainedComponents::empty(),
138        None,
139        |dir, is_framework| {
140            if !is_framework {
141                for (prefix, suffix) in &formats {
142                    let test = dir.join(format!("{prefix}{name}{suffix}"));
143                    if test.exists() {
144                        return ControlFlow::Break(test);
145                    }
146                }
147            }
148            ControlFlow::Continue(())
149        },
150    )
151    .break_value()
152}
153
154pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
155    try_find_native_static_library(sess, name, verbatim)
156        .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
157}
158
159fn find_bundled_library(
160    name: Symbol,
161    verbatim: Option<bool>,
162    kind: NativeLibKind,
163    has_cfg: bool,
164    tcx: TyCtxt<'_>,
165) -> Option<Symbol> {
166    let sess = tcx.sess;
167    if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
168        && tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
169        && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
170    {
171        let verbatim = verbatim.unwrap_or(false);
172        return find_native_static_library(name.as_str(), verbatim, sess)
173            .file_name()
174            .and_then(|s| s.to_str())
175            .map(Symbol::intern);
176    }
177    None
178}
179
180pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
181    let mut collector = Collector { tcx, libs: Vec::new() };
182    if tcx.sess.opts.unstable_opts.link_directives {
183        for module in tcx.foreign_modules(LOCAL_CRATE).values() {
184            collector.process_module(module);
185        }
186    }
187    collector.process_command_line();
188    collector.libs
189}
190
191pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
192    match lib.cfg {
193        Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
194        None => true,
195    }
196}
197
198struct Collector<'tcx> {
199    tcx: TyCtxt<'tcx>,
200    libs: Vec<NativeLib>,
201}
202
203impl<'tcx> Collector<'tcx> {
204    fn process_module(&mut self, module: &ForeignModule) {
205        let ForeignModule { def_id, abi, ref foreign_items } = *module;
206        let def_id = def_id.expect_local();
207
208        let sess = self.tcx.sess;
209
210        if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) {
211            return;
212        }
213
214        // Process all of the #[link(..)]-style arguments
215        let features = self.tcx.features();
216
217        for m in self.tcx.get_attrs(def_id, sym::link) {
218            let Some(items) = m.meta_item_list() else {
219                continue;
220            };
221
222            let mut name = None;
223            let mut kind = None;
224            let mut modifiers = None;
225            let mut cfg = None;
226            let mut wasm_import_module = None;
227            let mut import_name_type = None;
228            for item in items.iter() {
229                match item.name_or_empty() {
230                    sym::name => {
231                        if name.is_some() {
232                            sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
233                            continue;
234                        }
235                        let Some(link_name) = item.value_str() else {
236                            sess.dcx().emit_err(errors::LinkNameForm { span: item.span() });
237                            continue;
238                        };
239                        let span = item.name_value_literal_span().unwrap();
240                        if link_name.is_empty() {
241                            sess.dcx().emit_err(errors::EmptyLinkName { span });
242                        }
243                        name = Some((link_name, span));
244                    }
245                    sym::kind => {
246                        if kind.is_some() {
247                            sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
248                            continue;
249                        }
250                        let Some(link_kind) = item.value_str() else {
251                            sess.dcx().emit_err(errors::LinkKindForm { span: item.span() });
252                            continue;
253                        };
254
255                        let span = item.name_value_literal_span().unwrap();
256                        let link_kind = match link_kind.as_str() {
257                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
258                            "dylib" => NativeLibKind::Dylib { as_needed: None },
259                            "framework" => {
260                                if !sess.target.is_like_osx {
261                                    sess.dcx().emit_err(errors::LinkFrameworkApple { span });
262                                }
263                                NativeLibKind::Framework { as_needed: None }
264                            }
265                            "raw-dylib" => {
266                                if !sess.target.is_like_windows {
267                                    sess.dcx().emit_err(errors::RawDylibOnlyWindows { span });
268                                }
269                                NativeLibKind::RawDylib
270                            }
271                            "link-arg" => {
272                                if !features.link_arg_attribute() {
273                                    feature_err(
274                                        sess,
275                                        sym::link_arg_attribute,
276                                        span,
277                                        fluent_generated::metadata_link_arg_unstable,
278                                    )
279                                    .emit();
280                                }
281                                NativeLibKind::LinkArg
282                            }
283                            kind => {
284                                sess.dcx().emit_err(errors::UnknownLinkKind { span, kind });
285                                continue;
286                            }
287                        };
288                        kind = Some(link_kind);
289                    }
290                    sym::modifiers => {
291                        if modifiers.is_some() {
292                            sess.dcx()
293                                .emit_err(errors::MultipleLinkModifiers { span: item.span() });
294                            continue;
295                        }
296                        let Some(link_modifiers) = item.value_str() else {
297                            sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() });
298                            continue;
299                        };
300                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
301                    }
302                    sym::cfg => {
303                        if cfg.is_some() {
304                            sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
305                            continue;
306                        }
307                        let Some(link_cfg) = item.meta_item_list() else {
308                            sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
309                            continue;
310                        };
311                        let [link_cfg] = link_cfg else {
312                            sess.dcx()
313                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
314                            continue;
315                        };
316                        let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
317                            sess.dcx()
318                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
319                            continue;
320                        };
321                        if !features.link_cfg() {
322                            feature_err(
323                                sess,
324                                sym::link_cfg,
325                                item.span(),
326                                fluent_generated::metadata_link_cfg_unstable,
327                            )
328                            .emit();
329                        }
330                        cfg = Some(link_cfg.clone());
331                    }
332                    sym::wasm_import_module => {
333                        if wasm_import_module.is_some() {
334                            sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
335                            continue;
336                        }
337                        let Some(link_wasm_import_module) = item.value_str() else {
338                            sess.dcx().emit_err(errors::WasmImportForm { span: item.span() });
339                            continue;
340                        };
341                        wasm_import_module = Some((link_wasm_import_module, item.span()));
342                    }
343                    sym::import_name_type => {
344                        if import_name_type.is_some() {
345                            sess.dcx()
346                                .emit_err(errors::MultipleImportNameType { span: item.span() });
347                            continue;
348                        }
349                        let Some(link_import_name_type) = item.value_str() else {
350                            sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() });
351                            continue;
352                        };
353                        if self.tcx.sess.target.arch != "x86" {
354                            sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() });
355                            continue;
356                        }
357
358                        let link_import_name_type = match link_import_name_type.as_str() {
359                            "decorated" => PeImportNameType::Decorated,
360                            "noprefix" => PeImportNameType::NoPrefix,
361                            "undecorated" => PeImportNameType::Undecorated,
362                            import_name_type => {
363                                sess.dcx().emit_err(errors::UnknownImportNameType {
364                                    span: item.span(),
365                                    import_name_type,
366                                });
367                                continue;
368                            }
369                        };
370                        import_name_type = Some((link_import_name_type, item.span()));
371                    }
372                    _ => {
373                        sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() });
374                    }
375                }
376            }
377
378            // Do this outside the above loop so we don't depend on modifiers coming after kinds
379            let mut verbatim = None;
380            if let Some((modifiers, span)) = modifiers {
381                for modifier in modifiers.as_str().split(',') {
382                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
383                        Some(m) => (m, modifier.starts_with('+')),
384                        None => {
385                            sess.dcx().emit_err(errors::InvalidLinkModifier { span });
386                            continue;
387                        }
388                    };
389
390                    macro report_unstable_modifier($feature: ident) {
391                        if !features.$feature() {
392                            // FIXME: make this translatable
393                            #[expect(rustc::untranslatable_diagnostic)]
394                            feature_err(
395                                sess,
396                                sym::$feature,
397                                span,
398                                format!("linking modifier `{modifier}` is unstable"),
399                            )
400                            .emit();
401                        }
402                    }
403                    let assign_modifier = |dst: &mut Option<bool>| {
404                        if dst.is_some() {
405                            sess.dcx().emit_err(errors::MultipleModifiers { span, modifier });
406                        } else {
407                            *dst = Some(value);
408                        }
409                    };
410                    match (modifier, &mut kind) {
411                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
412                            assign_modifier(bundle)
413                        }
414                        ("bundle", _) => {
415                            sess.dcx().emit_err(errors::BundleNeedsStatic { span });
416                        }
417
418                        ("verbatim", _) => assign_modifier(&mut verbatim),
419
420                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
421                            assign_modifier(whole_archive)
422                        }
423                        ("whole-archive", _) => {
424                            sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span });
425                        }
426
427                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
428                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
429                            report_unstable_modifier!(native_link_modifiers_as_needed);
430                            assign_modifier(as_needed)
431                        }
432                        ("as-needed", _) => {
433                            sess.dcx().emit_err(errors::AsNeededCompatibility { span });
434                        }
435
436                        _ => {
437                            sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier });
438                        }
439                    }
440                }
441            }
442
443            if let Some((_, span)) = wasm_import_module {
444                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
445                    sess.dcx().emit_err(errors::IncompatibleWasmLink { span });
446                }
447            }
448
449            if wasm_import_module.is_some() {
450                (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
451            }
452            let Some((name, name_span)) = name else {
453                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span });
454                continue;
455            };
456
457            // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
458            if let Some((_, span)) = import_name_type {
459                if kind != Some(NativeLibKind::RawDylib) {
460                    sess.dcx().emit_err(errors::ImportNameTypeRaw { span });
461                }
462            }
463
464            let dll_imports = match kind {
465                Some(NativeLibKind::RawDylib) => {
466                    if name.as_str().contains('\0') {
467                        sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span });
468                    }
469                    foreign_items
470                        .iter()
471                        .map(|&child_item| {
472                            self.build_dll_import(
473                                abi,
474                                import_name_type.map(|(import_name_type, _)| import_name_type),
475                                child_item,
476                            )
477                        })
478                        .collect()
479                }
480                _ => {
481                    for &child_item in foreign_items {
482                        if self.tcx.def_kind(child_item).has_codegen_attrs()
483                            && self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
484                        {
485                            let link_ordinal_attr =
486                                self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
487                            sess.dcx().emit_err(errors::LinkOrdinalRawDylib {
488                                span: link_ordinal_attr.span,
489                            });
490                        }
491                    }
492
493                    Vec::new()
494                }
495            };
496
497            let kind = kind.unwrap_or(NativeLibKind::Unspecified);
498            let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx);
499            self.libs.push(NativeLib {
500                name,
501                filename,
502                kind,
503                cfg,
504                foreign_module: Some(def_id.to_def_id()),
505                verbatim,
506                dll_imports,
507            });
508        }
509    }
510
511    // Process libs passed on the command line
512    fn process_command_line(&mut self) {
513        // First, check for errors
514        let mut renames = FxHashSet::default();
515        for lib in &self.tcx.sess.opts.libs {
516            if let NativeLibKind::Framework { .. } = lib.kind
517                && !self.tcx.sess.target.is_like_osx
518            {
519                // Cannot check this when parsing options because the target is not yet available.
520                self.tcx.dcx().emit_err(errors::LibFrameworkApple);
521            }
522            if let Some(ref new_name) = lib.new_name {
523                let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
524                if new_name.is_empty() {
525                    self.tcx.dcx().emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
526                } else if !any_duplicate {
527                    self.tcx.dcx().emit_err(errors::RenamingNoLink { lib_name: &lib.name });
528                } else if !renames.insert(&lib.name) {
529                    self.tcx.dcx().emit_err(errors::MultipleRenamings { lib_name: &lib.name });
530                }
531            }
532        }
533
534        // Update kind and, optionally, the name of all native libraries
535        // (there may be more than one) with the specified name. If any
536        // library is mentioned more than once, keep the latest mention
537        // of it, so that any possible dependent libraries appear before
538        // it. (This ensures that the linker is able to see symbols from
539        // all possible dependent libraries before linking in the library
540        // in question.)
541        for passed_lib in &self.tcx.sess.opts.libs {
542            // If we've already added any native libraries with the same
543            // name, they will be pulled out into `existing`, so that we
544            // can move them to the end of the list below.
545            let mut existing = self
546                .libs
547                .extract_if(.., |lib| {
548                    if lib.name.as_str() == passed_lib.name {
549                        // FIXME: This whole logic is questionable, whether modifiers are
550                        // involved or not, library reordering and kind overriding without
551                        // explicit `:rename` in particular.
552                        if lib.has_modifiers() || passed_lib.has_modifiers() {
553                            match lib.foreign_module {
554                                Some(def_id) => {
555                                    self.tcx.dcx().emit_err(errors::NoLinkModOverride {
556                                        span: Some(self.tcx.def_span(def_id)),
557                                    })
558                                }
559                                None => self
560                                    .tcx
561                                    .dcx()
562                                    .emit_err(errors::NoLinkModOverride { span: None }),
563                            };
564                        }
565                        if passed_lib.kind != NativeLibKind::Unspecified {
566                            lib.kind = passed_lib.kind;
567                        }
568                        if let Some(new_name) = &passed_lib.new_name {
569                            lib.name = Symbol::intern(new_name);
570                        }
571                        lib.verbatim = passed_lib.verbatim;
572                        return true;
573                    }
574                    false
575                })
576                .collect::<Vec<_>>();
577            if existing.is_empty() {
578                // Add if not found
579                let new_name: Option<&str> = passed_lib.new_name.as_deref();
580                let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
581                let filename = find_bundled_library(
582                    name,
583                    passed_lib.verbatim,
584                    passed_lib.kind,
585                    false,
586                    self.tcx,
587                );
588                self.libs.push(NativeLib {
589                    name,
590                    filename,
591                    kind: passed_lib.kind,
592                    cfg: None,
593                    foreign_module: None,
594                    verbatim: passed_lib.verbatim,
595                    dll_imports: Vec::new(),
596                });
597            } else {
598                // Move all existing libraries with the same name to the
599                // end of the command line.
600                self.libs.append(&mut existing);
601            }
602        }
603    }
604
605    fn i686_arg_list_size(&self, item: DefId) -> usize {
606        let argument_types: &List<Ty<'_>> = self.tcx.instantiate_bound_regions_with_erased(
607            self.tcx
608                .type_of(item)
609                .instantiate_identity()
610                .fn_sig(self.tcx)
611                .inputs()
612                .map_bound(|slice| self.tcx.mk_type_list(slice)),
613        );
614
615        argument_types
616            .iter()
617            .map(|ty| {
618                let layout = self
619                    .tcx
620                    .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
621                    .expect("layout")
622                    .layout;
623                // In both stdcall and fastcall, we always round up the argument size to the
624                // nearest multiple of 4 bytes.
625                (layout.size().bytes_usize() + 3) & !3
626            })
627            .sum()
628    }
629
630    fn build_dll_import(
631        &self,
632        abi: ExternAbi,
633        import_name_type: Option<PeImportNameType>,
634        item: DefId,
635    ) -> DllImport {
636        let span = self.tcx.def_span(item);
637
638        // this logic is similar to `Target::adjust_abi` (in rustc_target/src/spec/mod.rs) but errors on unsupported inputs
639        let calling_convention = if self.tcx.sess.target.arch == "x86" {
640            match abi {
641                ExternAbi::C { .. } | ExternAbi::Cdecl { .. } => DllCallingConvention::C,
642                ExternAbi::Stdcall { .. } => {
643                    DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
644                }
645                // On Windows, `extern "system"` behaves like msvc's `__stdcall`.
646                // `__stdcall` only applies on x86 and on non-variadic functions:
647                // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
648                ExternAbi::System { .. } => {
649                    let c_variadic =
650                        self.tcx.type_of(item).instantiate_identity().fn_sig(self.tcx).c_variadic();
651
652                    if c_variadic {
653                        DllCallingConvention::C
654                    } else {
655                        DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
656                    }
657                }
658                ExternAbi::Fastcall { .. } => {
659                    DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
660                }
661                ExternAbi::Vectorcall { .. } => {
662                    DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
663                }
664                _ => {
665                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbiI686 { span });
666                }
667            }
668        } else {
669            match abi {
670                ExternAbi::C { .. } | ExternAbi::Win64 { .. } | ExternAbi::System { .. } => {
671                    DllCallingConvention::C
672                }
673                _ => {
674                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbi { span });
675                }
676            }
677        };
678
679        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
680        let import_name_type = codegen_fn_attrs
681            .link_ordinal
682            .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
683
684        DllImport {
685            name: codegen_fn_attrs.link_name.unwrap_or(self.tcx.item_name(item)),
686            import_name_type,
687            calling_convention,
688            span,
689            is_fn: self.tcx.def_kind(item).is_fn_like(),
690        }
691    }
692}