-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,
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
// 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 {
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
})
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.
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
.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,
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(),
}
}
}