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 | |
| 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.)
19 files changed, 436 insertions, 48 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 64416bced31..6ac7093b7de 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -12,7 +12,7 @@ use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_middle::middle::cstore::DllImport; +use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -208,10 +208,12 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { // have any \0 characters let import_name_vector: Vec<CString> = dll_imports .iter() - .map(if self.config.sess.target.arch == "x86" { - |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap() - } else { - |import: &DllImport| CString::new(import.name.to_string()).unwrap() + .map(|import: &DllImport| { + if self.config.sess.target.arch == "x86" { + LlvmArchiveBuilder::i686_decorated_name(import) + } else { + CString::new(import.name.to_string()).unwrap() + } }) .collect(); @@ -391,6 +393,21 @@ impl<'a> LlvmArchiveBuilder<'a> { ret } } + + fn i686_decorated_name(import: &DllImport) -> CString { + let name = import.name; + // We verified during construction that `name` does not contain any NULL characters, so the + // conversion to CString is guaranteed to succeed. + CString::new(match import.calling_convention { + DllCallingConvention::C => format!("_{}", name), + DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size), + DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size), + DllCallingConvention::Vectorcall(arg_list_size) => { + format!("{}@@{}", name, arg_list_size) + } + }) + .unwrap() + } } fn string_to_io_error(s: String) -> io::Error { 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 } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index cd4c394ae14..16b4d26b37b 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,8 +3,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::{DllImport, NativeLib}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::middle::cstore::{DllCallingConvention, DllImport, NativeLib}; +use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; @@ -199,22 +199,10 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { } if lib.kind == NativeLibKind::RawDylib { - match abi { - Abi::C { .. } => (), - Abi::Cdecl => (), - _ => { - if sess.target.arch == "x86" { - sess.span_fatal( - it.span, - r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#, - ); - } - } - }; lib.dll_imports.extend( foreign_mod_items .iter() - .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }), + .map(|child_item| self.build_dll_import(abi, child_item)), ); } @@ -396,4 +384,58 @@ impl Collector<'tcx> { } } } + + 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) + .fn_sig(self.tcx) + .inputs() + .map_bound(|slice| self.tcx.mk_type_list(slice.iter())), + ); + + argument_types + .iter() + .map(|ty| { + let layout = self + .tcx + .layout_of(ParamEnvAnd { param_env: ParamEnv::empty(), value: ty }) + .expect("layout") + .layout; + // In both stdcall and fastcall, we always round up the argument size to the + // nearest multiple of 4 bytes. + (layout.size.bytes_usize() + 3) & !3 + }) + .sum() + } + + fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef<'_>) -> DllImport { + let calling_convention = if self.tcx.sess.target.arch == "x86" { + match abi { + Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C, + Abi::Stdcall { .. } | Abi::System { .. } => { + DllCallingConvention::Stdcall(self.i686_arg_list_size(item)) + } + Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)), + // Vectorcall is intentionally not supported at this time. + _ => { + self.tcx.sess.span_fatal( + item.span, + r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#, + ); + } + } + } 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"#, + ); + } + } + }; + DllImport { name: item.ident.name, ordinal: None, calling_convention, span: item.span } + } } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 3c4c4a84d24..d69904f7b11 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -77,10 +77,29 @@ pub struct NativeLib { pub dll_imports: Vec<DllImport>, } -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] pub struct DllImport { pub name: Symbol, pub ordinal: Option<u16>, + /// Calling convention for the function. + /// + /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any + /// of the values, and we use `DllCallingConvention::C` to represent `"cdecl"`. + pub calling_convention: DllCallingConvention, + /// Span of import's "extern" declaration; used for diagnostics. + pub span: Span, +} + +/// Calling convention for a function defined in an external library. +/// +/// The usize value, where present, indicates the size of the function's argument list +/// in bytes. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +pub enum DllCallingConvention { + C, + Stdcall(usize), + Fastcall(usize), + Vectorcall(usize), } #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile new file mode 100644 index 00000000000..0f874333fa0 --- /dev/null +++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile @@ -0,0 +1,18 @@ +# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions. + +# only-i686-pc-windows-msvc + +-include ../../run-make-fulldeps/tools.mk + +all: + $(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c) + $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll + $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" + "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/output.txt output.txt +else + $(DIFF) output.txt "$(TMPDIR)"/output.txt +endif diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs b/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs new file mode 100644 index 00000000000..3710507f5e4 --- /dev/null +++ b/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs @@ -0,0 +1,5 @@ +extern crate raw_dylib_alt_calling_convention_test; + +fn main() { + raw_dylib_alt_calling_convention_test::library_function(); +} diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/extern.c b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c new file mode 100644 index 00000000000..8f64abf2fb5 --- /dev/null +++ b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c @@ -0,0 +1,123 @@ +#include <stdio.h> +#include <stdint.h> + +struct S { + uint8_t x; + int32_t y; +}; + +struct S2 { + int32_t x; + uint8_t y; +}; + +struct S3 { + uint8_t x[5]; +}; + +__declspec(dllexport) void __stdcall stdcall_fn_1(int i) { + printf("stdcall_fn_1(%d)\n", i); + fflush(stdout); +} + +__declspec(dllexport) void __stdcall stdcall_fn_2(uint8_t i, float f) { + printf("stdcall_fn_2(%d, %.1f)\n", i, f); + fflush(stdout); +} + +__declspec(dllexport) void __stdcall stdcall_fn_3(double d) { + printf("stdcall_fn_3(%.1f)\n", d); + fflush(stdout); +} + +__declspec(dllexport) void __stdcall stdcall_fn_4(uint8_t i, uint8_t j, float f) { + printf("stdcall_fn_4(%d, %d, %.1f)\n", i, j, f); + fflush(stdout); +} + +__declspec(dllexport) void __stdcall stdcall_fn_5(struct S s, int i) { + printf("stdcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i); + fflush(stdout); +} + +// Test that stdcall support works correctly with the nullable pointer optimization. +__declspec(dllexport) void __stdcall stdcall_fn_6(struct S* s) { + if (s) { + printf("stdcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y); + } else { + printf("stdcall_fn_6(null)\n"); + } + fflush(stdout); +} + +__declspec(dllexport) void __stdcall stdcall_fn_7(struct S2 s, int i) { + printf("stdcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i); + fflush(stdout); +} + +// Verify that we compute the correct amount of space in the argument list for a 5-byte struct. +__declspec(dllexport) void __stdcall stdcall_fn_8(struct S3 s, struct S3 t) { + printf("stdcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n", + s.x[0], s.x[1], s.x[2], s.x[3], s.x[4], + t.x[0], t.x[1], t.x[2], t.x[3], t.x[4] + ); + fflush(stdout); +} + +// test whether f64/double values are aligned on 4-byte or 8-byte boundaries. +__declspec(dllexport) void __stdcall stdcall_fn_9(uint8_t x, double y) { + printf("stdcall_fn_9(%d, %.1f)\n", x, y); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_1(int i) { + printf("fastcall_fn_1(%d)\n", i); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_2(uint8_t i, float f) { + printf("fastcall_fn_2(%d, %.1f)\n", i, f); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_3(double d) { + printf("fastcall_fn_3(%.1f)\n", d); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_4(uint8_t i, uint8_t j, float f) { + printf("fastcall_fn_4(%d, %d, %.1f)\n", i, j, f); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_5(struct S s, int i) { + printf("fastcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_6(struct S* s) { + if (s) { + printf("fastcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y); + } else { + printf("fastcall_fn_6(null)\n"); + } + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_7(struct S2 s, int i) { + printf("fastcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_8(struct S3 s, struct S3 t) { + printf("fastcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n", + s.x[0], s.x[1], s.x[2], s.x[3], s.x[4], + t.x[0], t.x[1], t.x[2], t.x[3], t.x[4] + ); + fflush(stdout); +} + +__declspec(dllexport) void __fastcall fastcall_fn_9(uint8_t x, double y) { + printf("fastcall_fn_9(%d, %.1f)\n", x, y); + fflush(stdout); +} diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs new file mode 100644 index 00000000000..ba0f1418aba --- /dev/null +++ b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs @@ -0,0 +1,71 @@ +#![feature(raw_dylib)] + +#[repr(C)] +#[derive(Clone)] +struct S { + x: u8, + y: i32, +} + +#[repr(C)] +#[derive(Clone)] +struct S2 { + x: i32, + y: u8, +} + +#[repr(C)] +#[derive(Clone)] +struct S3 { + x: [u8; 5], +} + +#[link(name = "extern", kind = "raw-dylib")] +extern "stdcall" { + fn stdcall_fn_1(i: i32); + fn stdcall_fn_2(c: u8, f: f32); + fn stdcall_fn_3(d: f64); + fn stdcall_fn_4(i: u8, j: u8, f: f32); + fn stdcall_fn_5(a: S, b: i32); + fn stdcall_fn_6(a: Option<&S>); + fn stdcall_fn_7(a: S2, b: i32); + fn stdcall_fn_8(a: S3, b: S3); + fn stdcall_fn_9(x: u8, y: f64); +} + +#[link(name = "extern", kind = "raw-dylib")] +extern "fastcall" { + fn fastcall_fn_1(i: i32); + fn fastcall_fn_2(c: u8, f: f32); + fn fastcall_fn_3(d: f64); + fn fastcall_fn_4(i: u8, j: u8, f: f32); + fn fastcall_fn_5(a: S, b: i32); + fn fastcall_fn_6(a: Option<&S>); + fn fastcall_fn_7(a: S2, b: i32); + fn fastcall_fn_8(a: S3, b: S3); + fn fastcall_fn_9(x: u8, y: f64); +} + +pub fn library_function() { + unsafe { + stdcall_fn_1(14); + stdcall_fn_2(16, 3.5); + stdcall_fn_3(3.5); + stdcall_fn_4(1, 2, 3.0); + stdcall_fn_5(S { x: 1, y: 2 }, 16); + stdcall_fn_6(Some(&S { x: 10, y: 12 })); + stdcall_fn_7(S2 { x: 15, y: 16 }, 3); + stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] }); + stdcall_fn_9(1, 3.0); + + fastcall_fn_1(14); + fastcall_fn_2(16, 3.5); + fastcall_fn_3(3.5); + fastcall_fn_4(1, 2, 3.0); + fastcall_fn_5(S { x: 1, y: 2 }, 16); + fastcall_fn_6(Some(&S { x: 10, y: 12 })); + fastcall_fn_7(S2 { x: 15, y: 16 }, 3); + fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] }); + fastcall_fn_9(1, 3.0); + } +} diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt new file mode 100644 index 00000000000..be598a22027 --- /dev/null +++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt @@ -0,0 +1,18 @@ +stdcall_fn_1(14) +stdcall_fn_2(16, 3.5) +stdcall_fn_3(3.5) +stdcall_fn_4(1, 2, 3.0) +stdcall_fn_5(S { x: 1, y: 2 }, 16) +stdcall_fn_6(S { x: 10, y: 12 }) +stdcall_fn_7(S2 { x: 15, y: 16 }, 3) +stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] }) +stdcall_fn_9(1, 3.0) +fastcall_fn_1(14) +fastcall_fn_2(16, 3.5) +fastcall_fn_3(3.5) +fastcall_fn_4(1, 2, 3.0) +fastcall_fn_5(S { x: 1, y: 2 }, 16) +fastcall_fn_6(S { x: 10, y: 12 }) +fastcall_fn_7(S2 { x: 15, y: 16 }, 3) +fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] }) +fastcall_fn_9(1, 3.0) diff --git a/src/test/run-make/raw-dylib/Makefile b/src/test/run-make/raw-dylib-c/Makefile index 7ce46fd9331..26ab4d34764 100644 --- a/src/test/run-make/raw-dylib/Makefile +++ b/src/test/run-make/raw-dylib-c/Makefile @@ -1,7 +1,6 @@ # Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc -# only-windows -# only-msvc +# only-windows-msvc -include ../../run-make-fulldeps/tools.mk diff --git a/src/test/run-make/raw-dylib/driver.rs b/src/test/run-make/raw-dylib-c/driver.rs index 4059ede11fc..4059ede11fc 100644 --- a/src/test/run-make/raw-dylib/driver.rs +++ b/src/test/run-make/raw-dylib-c/driver.rs diff --git a/src/test/run-make/raw-dylib/extern_1.c b/src/test/run-make/raw-dylib-c/extern_1.c index 72737c086eb..72737c086eb 100644 --- a/src/test/run-make/raw-dylib/extern_1.c +++ b/src/test/run-make/raw-dylib-c/extern_1.c diff --git a/src/test/run-make/raw-dylib/extern_2.c b/src/test/run-make/raw-dylib-c/extern_2.c index ae87fc3f821..ae87fc3f821 100644 --- a/src/test/run-make/raw-dylib/extern_2.c +++ b/src/test/run-make/raw-dylib-c/extern_2.c diff --git a/src/test/run-make/raw-dylib/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs index d8e6301f38e..d8e6301f38e 100644 --- a/src/test/run-make/raw-dylib/lib.rs +++ b/src/test/run-make/raw-dylib-c/lib.rs diff --git a/src/test/run-make/raw-dylib/output.txt b/src/test/run-make/raw-dylib-c/output.txt index 7800cba1872..7800cba1872 100644 --- a/src/test/run-make/raw-dylib/output.txt +++ b/src/test/run-make/raw-dylib-c/output.txt diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.rs b/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.rs new file mode 100644 index 00000000000..3f7597498ba --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.rs @@ -0,0 +1,19 @@ +// only-i686-pc-windows-msvc +// compile-flags: --crate-type lib --emit link +#![allow(clashing_extern_declarations)] +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); + //~^ ERROR multiple definitions of external function `f` from library `foo.dll` have different calling conventions +} + +pub fn lib_main() { + #[link(name = "foo", kind = "raw-dylib")] + extern "stdcall" { + fn f(x: i32); + } + + unsafe { f(42); } +} diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.stderr b/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.stderr new file mode 100644 index 00000000000..91f6f0cf722 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-definitions.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multiple-definitions.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + +error: multiple definitions of external function `f` from library `foo.dll` have different calling conventions + --> $DIR/multiple-definitions.rs:8:5 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs new file mode 100644 index 00000000000..e5a5ac2eb2b --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs @@ -0,0 +1,13 @@ +// only-x86_64-pc-windows-msvc +// compile-flags: --crate-type lib --emit link +#![allow(incomplete_features)] +#![feature(raw_dylib)] +#[link(name = "foo", kind = "raw-dylib")] +extern "stdcall" { + fn f(x: i32); + //~^ ERROR ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr new file mode 100644 index 00000000000..fc9008128ae --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr @@ -0,0 +1,8 @@ +error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture + --> $DIR/unsupported-abi.rs:7:5 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + |
