@@ -3,7 +3,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
33use rustc_errors:: Handler ;
44use rustc_fs_util:: fix_windows_verbatim_for_gcc;
55use rustc_hir:: def_id:: CrateNum ;
6- use rustc_middle:: middle:: cstore:: DllImport ;
6+ use rustc_middle:: middle:: cstore:: { DllCallingConvention , DllImport } ;
77use rustc_middle:: middle:: dependency_format:: Linkage ;
88use rustc_session:: config:: { self , CFGuard , CrateType , DebugInfo , LdImpl , Strip } ;
99use rustc_session:: config:: { OutputFilenames , OutputType , PrintRequest } ;
@@ -34,8 +34,8 @@ use object::write::Object;
3434use object:: { Architecture , BinaryFormat , Endianness , FileFlags , SectionFlags , SectionKind } ;
3535use tempfile:: Builder as TempFileBuilder ;
3636
37- use std:: cmp:: Ordering ;
3837use std:: ffi:: OsString ;
38+ use std:: iter:: FromIterator ;
3939use std:: path:: { Path , PathBuf } ;
4040use std:: process:: { ExitStatus , Output , Stdio } ;
4141use std:: { ascii, char, env, fmt, fs, io, mem, str} ;
@@ -259,7 +259,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
259259 }
260260
261261 for ( raw_dylib_name, raw_dylib_imports) in
262- collate_raw_dylibs ( & codegen_results. crate_info . used_libraries )
262+ collate_raw_dylibs ( sess , & codegen_results. crate_info . used_libraries )
263263 {
264264 ab. inject_dll_import_lib ( & raw_dylib_name, & raw_dylib_imports, tmpdir) ;
265265 }
@@ -451,8 +451,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
451451/// then the CodegenResults value contains one NativeLib instance for each block. However, the
452452/// linker appears to expect only a single import library for each library used, so we need to
453453/// collate the symbols together by library name before generating the import libraries.
454- fn collate_raw_dylibs ( used_libraries : & [ NativeLib ] ) -> Vec < ( String , Vec < DllImport > ) > {
455- let mut dylib_table: FxHashMap < String , FxHashSet < Symbol > > = FxHashMap :: default ( ) ;
454+ fn collate_raw_dylibs (
455+ sess : & Session ,
456+ used_libraries : & [ NativeLib ] ,
457+ ) -> Vec < ( String , Vec < DllImport > ) > {
458+ let mut dylib_table: FxHashMap < String , FxHashSet < DllImport > > = FxHashMap :: default ( ) ;
456459
457460 for lib in used_libraries {
458461 if lib. kind == NativeLibKind :: RawDylib {
@@ -464,35 +467,51 @@ fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImpor
464467 } else {
465468 format ! ( "{}.dll" , name)
466469 } ;
467- dylib_table
468- . entry ( name)
469- . or_default ( )
470- . extend ( lib. dll_imports . iter ( ) . map ( |import| import. name ) ) ;
470+ dylib_table. entry ( name) . or_default ( ) . extend ( lib. dll_imports . iter ( ) . cloned ( ) ) ;
471471 }
472472 }
473473
474- // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out
475- // what we should do if we have two DllImport values with the same name but different
476- // ordinals.
477- let mut result = dylib_table
474+ // Rustc already signals an error if we have two imports with the same name but different
475+ // calling conventions (or function signatures), so we don't have pay attention to those
476+ // when ordering.
477+ // FIXME: when we add support for ordinals, figure out if we need to do anything if we
478+ // have two DllImport values with the same name but different ordinals.
479+ let mut result: Vec < ( String , Vec < DllImport > ) > = dylib_table
478480 . into_iter ( )
479- . map ( |( lib_name, imported_names) | {
480- let mut names = imported_names
481- . iter ( )
482- . map ( |name| DllImport { name : * name, ordinal : None } )
483- . collect :: < Vec < _ > > ( ) ;
484- names. sort_unstable_by ( |a : & DllImport , b : & DllImport | {
485- match a. name . as_str ( ) . cmp ( & b. name . as_str ( ) ) {
486- Ordering :: Equal => a. ordinal . cmp ( & b. ordinal ) ,
487- x => x,
488- }
489- } ) ;
490- ( lib_name, names)
481+ . map ( |( lib_name, import_table) | {
482+ let mut imports = Vec :: from_iter ( import_table. into_iter ( ) ) ;
483+ imports. sort_unstable_by_key ( |x : & DllImport | x. name . as_str ( ) ) ;
484+ ( lib_name, imports)
491485 } )
492486 . collect :: < Vec < _ > > ( ) ;
493487 result. sort_unstable_by ( |a : & ( String , Vec < DllImport > ) , b : & ( String , Vec < DllImport > ) | {
494488 a. 0 . cmp ( & b. 0 )
495489 } ) ;
490+ let result = result;
491+
492+ // Check for multiple imports with the same name but different calling conventions or
493+ // (when relevant) argument list sizes. Rustc only signals an error for this if the
494+ // declarations are at the same scope level; if one shadows the other, we only get a lint
495+ // warning.
496+ for ( library, imports) in & result {
497+ let mut import_table: FxHashMap < Symbol , DllCallingConvention > = FxHashMap :: default ( ) ;
498+ for import in imports {
499+ if let Some ( old_convention) =
500+ import_table. insert ( import. name , import. calling_convention )
501+ {
502+ if import. calling_convention != old_convention {
503+ sess. span_fatal (
504+ import. span ,
505+ & format ! (
506+ "multiple definitions of external function `{}` from library `{}` have different calling conventions" ,
507+ import. name,
508+ library,
509+ ) ) ;
510+ }
511+ }
512+ }
513+ }
514+
496515 result
497516}
498517
0 commit comments