diff options
| author | bors <bors@rust-lang.org> | 2021-07-09 23:24:21 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-07-09 23:24:21 +0000 |
| commit | 8d9d4c87d677552ae52e2d58034e4be199b5a6d2 (patch) | |
| tree | 634db4e9ad0c606cf2c95e7f256da1121b18fea9 /compiler/rustc_codegen_ssa/src | |
| parent | 240ff4c4a0d0936c9eeb783fa9ff5c0507a6ffb4 (diff) | |
| parent | a867dd4c7e65beb1453fcff9e252e7ab19f0e1d0 (diff) | |
| download | rust-8d9d4c87d677552ae52e2d58034e4be199b5a6d2.tar.gz rust-8d9d4c87d677552ae52e2d58034e4be199b5a6d2.zip | |
Auto merge of #86419 - ricobbe:raw-dylib-stdcall, r=petrochenkov
Add support for raw-dylib with stdcall, fastcall functions Next stage of work for #58713: allow `extern "stdcall"` and `extern "fastcall"` with `#[link(kind = "raw-dylib")]`. I've deliberately omitted support for vectorcall, as that doesn't currently work, and I wanted to get this out for review. (I haven't really investigated the vectorcall failure much yet, but at first (very cursory) glance it appears that the problem is elsewhere.)
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 69 |
1 files changed, 44 insertions, 25 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 59447e9de13..f9efa448c93 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,7 +3,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::Handler; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::DllImport; +use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -34,8 +34,8 @@ use object::write::Object; use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind}; use tempfile::Builder as TempFileBuilder; -use std::cmp::Ordering; use std::ffi::OsString; +use std::iter::FromIterator; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -259,7 +259,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(&codegen_results.crate_info.used_libraries) + collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries) { ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); } @@ -451,8 +451,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( /// then the CodegenResults value contains one NativeLib instance for each block. However, the /// linker appears to expect only a single import library for each library used, so we need to /// collate the symbols together by library name before generating the import libraries. -fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> { - let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default(); +fn collate_raw_dylibs( + sess: &Session, + used_libraries: &[NativeLib], +) -> Vec<(String, Vec<DllImport>)> { + let mut dylib_table: FxHashMap<String, FxHashSet<DllImport>> = FxHashMap::default(); for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { @@ -464,35 +467,51 @@ fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImpor } else { format!("{}.dll", name) }; - dylib_table - .entry(name) - .or_default() - .extend(lib.dll_imports.iter().map(|import| import.name)); + dylib_table.entry(name).or_default().extend(lib.dll_imports.iter().cloned()); } } - // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out - // what we should do if we have two DllImport values with the same name but different - // ordinals. - let mut result = dylib_table + // Rustc already signals an error if we have two imports with the same name but different + // calling conventions (or function signatures), so we don't have pay attention to those + // when ordering. + // FIXME: when we add support for ordinals, figure out if we need to do anything if we + // have two DllImport values with the same name but different ordinals. + let mut result: Vec<(String, Vec<DllImport>)> = dylib_table .into_iter() - .map(|(lib_name, imported_names)| { - let mut names = imported_names - .iter() - .map(|name| DllImport { name: *name, ordinal: None }) - .collect::<Vec<_>>(); - names.sort_unstable_by(|a: &DllImport, b: &DllImport| { - match a.name.as_str().cmp(&b.name.as_str()) { - Ordering::Equal => a.ordinal.cmp(&b.ordinal), - x => x, - } - }); - (lib_name, names) + .map(|(lib_name, import_table)| { + let mut imports = Vec::from_iter(import_table.into_iter()); + imports.sort_unstable_by_key(|x: &DllImport| x.name.as_str()); + (lib_name, imports) }) .collect::<Vec<_>>(); result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| { a.0.cmp(&b.0) }); + let result = result; + + // Check for multiple imports with the same name but different calling conventions or + // (when relevant) argument list sizes. Rustc only signals an error for this if the + // declarations are at the same scope level; if one shadows the other, we only get a lint + // warning. + for (library, imports) in &result { + let mut import_table: FxHashMap<Symbol, DllCallingConvention> = FxHashMap::default(); + for import in imports { + if let Some(old_convention) = + import_table.insert(import.name, import.calling_convention) + { + if import.calling_convention != old_convention { + sess.span_fatal( + import.span, + &format!( + "multiple definitions of external function `{}` from library `{}` have different calling conventions", + import.name, + library, + )); + } + } + } + } + result } |
