Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of import_name_type #100732

Merged
merged 1 commit into from
Aug 27, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 10 additions & 24 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
@@ -8,10 +8,11 @@ use std::path::{Path, PathBuf};
use std::ptr;
use std::str;

use crate::common;
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use rustc_session::cstore::{DllCallingConvention, DllImport};
use rustc_session::cstore::DllImport;
use rustc_session::Session;

/// Helper for adding many files to an archive.
@@ -111,21 +112,18 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
};

let target = &sess.target;
let mingw_gnu_toolchain = target.vendor == "pc"
&& target.os == "windows"
&& target.env == "gnu"
&& target.abi.is_empty();
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);

let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
if sess.target.arch == "x86" {
(
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
import.ordinal,
common::i686_decorated_name(import, mingw_gnu_toolchain, false),
import.ordinal(),
)
} else {
(import.name.to_string(), import.ordinal)
(import.name.to_string(), import.ordinal())
}
})
.collect();
@@ -159,6 +157,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
}
};

// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
// able to control the *exact* spelling of each of the symbols that are being imported:
// hence we don't want `dlltool` adding leading underscores automatically.
let dlltool = find_binutils_dlltool(sess);
let result = std::process::Command::new(dlltool)
.args([
@@ -168,6 +169,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
lib_name,
"-l",
output_path.to_str().unwrap(),
"--no-leading-underscore",
])
.output();

@@ -322,22 +324,6 @@ impl<'a> LlvmArchiveBuilder<'a> {
ret
}
}

fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
let name = import.name;
let prefix = if mingw { "" } else { "_" };

match import.calling_convention {
DllCallingConvention::C => format!("{}{}", prefix, name),
DllCallingConvention::Stdcall(arg_list_size) => {
format!("{}{}@{}", prefix, name, arg_list_size)
}
DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
DllCallingConvention::Vectorcall(arg_list_size) => {
format!("{}@@{}", name, arg_list_size)
}
}
}
}

fn string_to_io_error(s: String) -> io::Error {
12 changes: 9 additions & 3 deletions compiler/rustc_codegen_llvm/src/callee.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;
@@ -79,13 +80,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
llfn
}
} else {
let llfn = cx.declare_fn(sym, fn_abi);
let instance_def_id = instance.def_id();
let llfn = if tcx.sess.target.arch == "x86" &&
let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
{
cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi)
} else {
cx.declare_fn(sym, fn_abi)
};
debug!("get_fn: not casting pointer!");

attributes::from_fn_attrs(cx, llfn, instance);

let instance_def_id = instance.def_id();

// Apply an appropriate linkage/visibility value to our item that we
// just declared.
//
76 changes: 76 additions & 0 deletions compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
@@ -10,12 +10,17 @@ use crate::value::Value;
use rustc_ast::Mutability;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
use rustc_target::spec::Target;

use libc::{c_char, c_uint};
use std::fmt::Write;
use tracing::debug;

/*
@@ -357,3 +362,74 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> {
unsafe { llvm::LLVMIsAConstantInt(v) }
}

pub(crate) fn get_dllimport<'tcx>(
tcx: TyCtxt<'tcx>,
id: DefId,
name: &str,
) -> Option<&'tcx DllImport> {
tcx.native_library(id)
.map(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
.flatten()
}

pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool {
target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
}

pub(crate) fn i686_decorated_name(
dll_import: &DllImport,
mingw: bool,
disable_name_mangling: bool,
) -> String {
let name = dll_import.name.as_str();

let (add_prefix, add_suffix) = match dll_import.import_name_type {
Some(PeImportNameType::NoPrefix) => (false, true),
Some(PeImportNameType::Undecorated) => (false, false),
_ => (true, true),
};

// Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
let mut decorated_name = String::with_capacity(name.len() + 6);

if disable_name_mangling {
// LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
decorated_name.push('\x01');
}

let prefix = if add_prefix && dll_import.is_fn {
match dll_import.calling_convention {
DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
DllCallingConvention::Stdcall(_) => (!mingw
|| dll_import.import_name_type == Some(PeImportNameType::Decorated))
.then_some('_'),
DllCallingConvention::Fastcall(_) => Some('@'),
}
} else if !dll_import.is_fn && !mingw {
// For static variables, prefix with '_' on MSVC.
Some('_')
} else {
None
};
if let Some(prefix) = prefix {
decorated_name.push(prefix);
}

decorated_name.push_str(name);

if add_suffix && dll_import.is_fn {
match dll_import.calling_convention {
DllCallingConvention::C => {}
DllCallingConvention::Stdcall(arg_list_size)
| DllCallingConvention::Fastcall(arg_list_size) => {
write!(&mut decorated_name, "@{}", arg_list_size).unwrap();
}
DllCallingConvention::Vectorcall(arg_list_size) => {
write!(&mut decorated_name, "@@{}", arg_list_size).unwrap();
}
}
}

decorated_name
}
12 changes: 8 additions & 4 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::base;
use crate::common::CodegenCx;
use crate::common::{self, CodegenCx};
use crate::debuginfo;
use crate::llvm::{self, True};
use crate::llvm_util;
@@ -160,7 +160,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
attrs: &CodegenFnAttrs,
ty: Ty<'tcx>,
sym: &str,
span_def_id: DefId,
def_id: DefId,
) -> &'ll Value {
let llty = cx.layout_of(ty).llvm_type(cx);
if let Some(linkage) = attrs.linkage {
@@ -175,7 +175,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
cx.layout_of(mt.ty).llvm_type(cx)
} else {
cx.sess().span_fatal(
cx.tcx.def_span(span_def_id),
cx.tcx.def_span(def_id),
"must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
)
};
@@ -194,14 +194,18 @@ fn check_and_apply_linkage<'ll, 'tcx>(
real_name.push_str(sym);
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
cx.sess().span_fatal(
cx.tcx.def_span(span_def_id),
cx.tcx.def_span(def_id),
&format!("symbol `{}` is already defined", &sym),
)
});
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
llvm::LLVMSetInitializer(g2, g1);
g2
}
} else if cx.tcx.sess.target.arch == "x86" &&
let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
{
cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty)
} else {
// Generate an external declaration.
// FIXME(nagisa): investigate whether it can be changed into define_global
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
@@ -335,7 +335,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ABI, linking, symbols, and FFI
ungated!(
link, Normal,
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
DuplicatesOk,
),
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
79 changes: 74 additions & 5 deletions compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
use rustc_session::parse::feature_err;
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
@@ -61,6 +61,7 @@ impl<'tcx> Collector<'tcx> {
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() {
match item.name_or_empty() {
sym::name => {
@@ -199,9 +200,51 @@ impl<'tcx> Collector<'tcx> {
};
wasm_import_module = Some((link_wasm_import_module, item.span()));
}
sym::import_name_type => {
if import_name_type.is_some() {
let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute";
sess.span_err(item.span(), msg);
continue;
}
let Some(link_import_name_type) = item.value_str() else {
let msg = "import name type must be of the form `import_name_type = \"string\"`";
sess.span_err(item.span(), msg);
continue;
};
if self.tcx.sess.target.arch != "x86" {
let msg = "import name type is only supported on x86";
sess.span_err(item.span(), msg);
continue;
}

let link_import_name_type = match link_import_name_type.as_str() {
"decorated" => PeImportNameType::Decorated,
"noprefix" => PeImportNameType::NoPrefix,
"undecorated" => PeImportNameType::Undecorated,
import_name_type => {
let msg = format!(
"unknown import name type `{import_name_type}`, expected one of: \
decorated, noprefix, undecorated"
);
sess.span_err(item.span(), msg);
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()));
}
_ => {
let msg = "unexpected `#[link]` argument, expected one of: \
name, kind, modifiers, cfg, wasm_import_module";
name, kind, modifiers, cfg, wasm_import_module, import_name_type";
sess.span_err(item.span(), msg);
}
}
@@ -315,6 +358,14 @@ impl<'tcx> Collector<'tcx> {
.emit();
}

// 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) {
let msg = "import name type can only be used with link kind `raw-dylib`";
sess.span_err(span, msg);
}
}

let dll_imports = match kind {
Some(NativeLibKind::RawDylib) => {
if let Some((name, span)) = name && name.as_str().contains('\0') {
@@ -325,7 +376,13 @@ impl<'tcx> Collector<'tcx> {
}
foreign_mod_items
.iter()
.map(|child_item| self.build_dll_import(abi, child_item))
.map(|child_item| {
self.build_dll_import(
abi,
import_name_type.map(|(import_name_type, _)| import_name_type),
child_item,
)
})
.collect()
}
_ => {
@@ -486,7 +543,12 @@ impl<'tcx> Collector<'tcx> {
.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,
@@ -518,11 +580,18 @@ impl<'tcx> Collector<'tcx> {
}
};

let import_name_type = self
.tcx
.codegen_fn_attrs(item.id.def_id)
.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,
import_name_type,
calling_convention,
span: item.span,
is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
}
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
@@ -341,7 +341,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
assert_eq!(cnum, LOCAL_CRATE);
false
},
native_library_kind: |tcx, id| {
native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind),
native_library: |tcx, id| {
tcx.native_libraries(id.krate)
.iter()
.filter(|lib| native_libs::relevant_lib(&tcx.sess, lib))
@@ -355,7 +356,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
.foreign_items
.contains(&id)
})
.map(|l| l.kind)
},
native_libraries: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1566,6 +1566,9 @@ rustc_queries! {
-> Option<NativeLibKind> {
desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
}
query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
desc { |tcx| "native_library({})", tcx.def_path_str(def_id) }
}

/// Does lifetime resolution, but does not descend into trait items. This
/// should only be used for resolving lifetimes of on trait definitions,
33 changes: 32 additions & 1 deletion compiler/rustc_session/src/cstore.rs
Original file line number Diff line number Diff line change
@@ -81,17 +81,48 @@ impl NativeLib {
}
}

/// Different ways that the PE Format can decorate a symbol name.
/// From <https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-name-type>
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq, Eq)]
pub enum PeImportNameType {
/// IMPORT_ORDINAL
/// Uses the ordinal (i.e., a number) rather than the name.
Ordinal(u16),
/// Same as IMPORT_NAME
/// Name is decorated with all prefixes and suffixes.
Decorated,
/// Same as IMPORT_NAME_NOPREFIX
/// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept.
NoPrefix,
/// Same as IMPORT_NAME_UNDECORATE
/// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all
/// trailing characters) are skipped.
Undecorated,
}

#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
pub struct DllImport {
pub name: Symbol,
pub ordinal: Option<u16>,
pub import_name_type: Option<PeImportNameType>,
/// 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,
/// Is this for a function (rather than a static variable).
pub is_fn: bool,
}

impl DllImport {
pub fn ordinal(&self) -> Option<u16> {
if let Some(PeImportNameType::Ordinal(ordinal)) = self.import_name_type {
Some(ordinal)
} else {
None
}
}
}

/// Calling convention for a function defined in an external library.
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -803,6 +803,7 @@ symbols! {
impl_trait_in_bindings,
implied_by,
import,
import_name_type,
import_shadowing,
imported_main,
in_band_lifetimes,
22 changes: 22 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.

# only-x86
# only-windows

-include ../../run-make-fulldeps/tools.mk

all:
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
ifdef IS_MSVC
$(CC) "$(TMPDIR)"/extern.obj extern.msvc.def -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
else
$(CC) "$(TMPDIR)"/extern.obj extern.gnu.def --no-leading-underscore -shared -o "$(TMPDIR)"/extern.dll
endif
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt

ifdef RUSTC_BLESS_TEST
cp "$(TMPDIR)"/output.txt output.txt
else
$(DIFF) output.txt "$(TMPDIR)"/output.txt
endif
79 changes: 79 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#![feature(raw_dylib)]

#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
extern "C" {
fn cdecl_fn_undecorated(i: i32);
static mut extern_variable_undecorated: i32;
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
extern "C" {
fn cdecl_fn_noprefix(i: i32);
static mut extern_variable_noprefix: i32;
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
extern "C" {
fn cdecl_fn_decorated(i: i32);
static mut extern_variable_decorated: i32;
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
extern "stdcall" {
fn stdcall_fn_undecorated(i: i32);
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
extern "stdcall" {
fn stdcall_fn_noprefix(i: i32);
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
extern "stdcall" {
fn stdcall_fn_decorated(i: i32);
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
extern "fastcall" {
fn fastcall_fn_undecorated(i: i32);
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
extern "fastcall" {
fn fastcall_fn_noprefix(i: i32);
}

#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
extern "fastcall" {
fn fastcall_fn_decorated(i: i32);
}

#[link(name = "extern", kind = "raw-dylib")]
extern {
fn print_extern_variable_undecorated();
fn print_extern_variable_noprefix();
fn print_extern_variable_decorated();
}

pub fn main() {
unsafe {
cdecl_fn_undecorated(1);
cdecl_fn_noprefix(2);
cdecl_fn_decorated(3);

stdcall_fn_undecorated(4);
stdcall_fn_noprefix(5);
stdcall_fn_decorated(6);

fastcall_fn_undecorated(7);
fastcall_fn_noprefix(8);
fastcall_fn_decorated(9);

extern_variable_undecorated = 42;
print_extern_variable_undecorated();
extern_variable_noprefix = 43;
print_extern_variable_noprefix();
extern_variable_decorated = 44;
print_extern_variable_decorated();
}
}
65 changes: 65 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/extern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdint.h>

void _cdecl cdecl_fn_undecorated(int i) {
printf("cdecl_fn_undecorated(%d)\n", i);
fflush(stdout);
}

void _cdecl cdecl_fn_noprefix(int i) {
printf("cdecl_fn_noprefix(%d)\n", i);
fflush(stdout);
}

void _cdecl cdecl_fn_decorated(int i) {
printf("cdecl_fn_decorated(%d)\n", i);
fflush(stdout);
}

void __stdcall stdcall_fn_undecorated(int i) {
printf("stdcall_fn_undecorated(%d)\n", i);
fflush(stdout);
}

void __stdcall stdcall_fn_noprefix(int i) {
printf("stdcall_fn_noprefix(%d)\n", i);
fflush(stdout);
}

void __stdcall stdcall_fn_decorated(int i) {
printf("stdcall_fn_decorated(%d)\n", i);
fflush(stdout);
}

void __fastcall fastcall_fn_undecorated(int i) {
printf("fastcall_fn_undecorated(%d)\n", i);
fflush(stdout);
}

void __fastcall fastcall_fn_noprefix(int i) {
printf("fastcall_fn_noprefix(%d)\n", i);
fflush(stdout);
}

void __fastcall fastcall_fn_decorated(int i) {
printf("fastcall_fn_decorated(%d)\n", i);
fflush(stdout);
}

int extern_variable_undecorated = 0;
__declspec(dllexport) void print_extern_variable_undecorated() {
printf("extern_variable_undecorated value: %d\n", extern_variable_undecorated);
fflush(stdout);
}

int extern_variable_noprefix = 0;
__declspec(dllexport) void print_extern_variable_noprefix() {
printf("extern_variable_noprefix value: %d\n", extern_variable_noprefix);
fflush(stdout);
}

int extern_variable_decorated = 0;
__declspec(dllexport) void print_extern_variable_decorated() {
printf("extern_variable_decorated value: %d\n", extern_variable_decorated);
fflush(stdout);
}
18 changes: 18 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
LIBRARY extern
EXPORTS
cdecl_fn_undecorated
cdecl_fn_noprefix
cdecl_fn_decorated
stdcall_fn_undecorated
stdcall_fn_noprefix@4
fastcall_fn_undecorated
@fastcall_fn_decorated@4

;ld doesn't handle fully-decorated stdcall, or no-prefix fastcall
_stdcall_fn_decorated@4=stdcall_fn_decorated@4
fastcall_fn_noprefix@4=@fastcall_fn_noprefix@4

;Variables are never decorated
extern_variable_undecorated
extern_variable_noprefix
extern_variable_decorated
18 changes: 18 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
LIBRARY extern
EXPORTS
cdecl_fn_undecorated
cdecl_fn_noprefix
cdecl_fn_decorated
stdcall_fn_undecorated
_stdcall_fn_decorated@4
fastcall_fn_undecorated
@fastcall_fn_decorated@4

;MSVC doesn't seem to recognize the "no prefix" syntax.
stdcall_fn_noprefix@4=_stdcall_fn_noprefix@4
fastcall_fn_noprefix@4=@fastcall_fn_noprefix@4

;Variables are never decorated
extern_variable_undecorated
extern_variable_noprefix
extern_variable_decorated
12 changes: 12 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cdecl_fn_undecorated(1)
cdecl_fn_noprefix(2)
cdecl_fn_decorated(3)
stdcall_fn_undecorated(4)
stdcall_fn_noprefix(5)
stdcall_fn_decorated(6)
fastcall_fn_undecorated(7)
fastcall_fn_noprefix(8)
fastcall_fn_decorated(9)
extern_variable_undecorated value: 42
extern_variable_noprefix value: 43
extern_variable_decorated value: 44
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// only-windows
// only-x86
#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
//~^ ERROR link kind `raw-dylib` is unstable
//~| ERROR import name type is unstable
extern "C" {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0658]: link kind `raw-dylib` is unstable
--> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
| ^^^^^^^^^^^
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
= help: add `#![feature(raw_dylib)]` to the crate attributes to enable

error[E0658]: import name type is unstable
--> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
| ^^^^^^^^^^^
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
= help: add `#![feature(raw_dylib)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
4 changes: 2 additions & 2 deletions src/test/ui/linkage-attr/link-attr-validation-early.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
--> $DIR/link-attr-validation-early.rs:2:1
|
LL | #[link]
@@ -8,7 +8,7 @@ LL | #[link]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>

error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
--> $DIR/link-attr-validation-early.rs:4:1
|
LL | #[link = "foo"]
4 changes: 2 additions & 2 deletions src/test/ui/linkage-attr/link-attr-validation-late.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
--> $DIR/link-attr-validation-late.rs:5:22
|
LL | #[link(name = "...", "literal")]
| ^^^^^^^^^

error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
--> $DIR/link-attr-validation-late.rs:6:22
|
LL | #[link(name = "...", unknown)]
4 changes: 2 additions & 2 deletions src/test/ui/malformed/malformed-regressions.stderr
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ LL | #[inline = ""]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>

error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
--> $DIR/malformed-regressions.rs:7:1
|
LL | #[link]
@@ -35,7 +35,7 @@ LL | #[link]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>

error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
--> $DIR/malformed-regressions.rs:9:1
|
LL | #[link = ""]
10 changes: 10 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// only-windows
// only-x86
#![feature(raw_dylib)]
//~^ WARN the feature `raw_dylib` is incomplete

#[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
//~^ ERROR import name type must be of the form `import_name_type = "string"`
extern "C" { }

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/import-name-type-invalid-format.rs:3: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: import name type must be of the form `import_name_type = "string"`
--> $DIR/import-name-type-invalid-format.rs:6:42
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
| ^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted

11 changes: 11 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// ignore-tidy-linelength
// only-windows
// only-x86
#![feature(raw_dylib)]
//~^ WARN the feature `raw_dylib` is incomplete

#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
//~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
extern "C" { }

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/import-name-type-multiple.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 `import_name_type` arguments in a single `#[link]` attribute
--> $DIR/import-name-type-multiple.rs:7:74
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted

10 changes: 10 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// only-windows
// only-x86
#![feature(raw_dylib)]
//~^ WARN the feature `raw_dylib` is incomplete

#[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
//~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
extern "C" { }

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/import-name-type-unknown-value.rs:3: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: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
--> $DIR/import-name-type-unknown-value.rs:6:42
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// only-windows
// only-x86
#![feature(raw_dylib)]
//~^ WARN the feature `raw_dylib` is incomplete

#[link(name = "foo", import_name_type = "decorated")]
//~^ ERROR import name type can only be used with link kind `raw-dylib`
extern "C" { }

#[link(name = "bar", kind = "static", import_name_type = "decorated")]
//~^ ERROR import name type can only be used with link kind `raw-dylib`
extern "C" { }

// Specifying `import_name_type` before `kind` shouldn't raise an error.
#[link(name = "bar", import_name_type = "decorated", kind = "raw-dylib")]
extern "C" { }

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/import-name-type-unsupported-link-kind.rs:3: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: import name type can only be used with link kind `raw-dylib`
--> $DIR/import-name-type-unsupported-link-kind.rs:6:22
|
LL | #[link(name = "foo", import_name_type = "decorated")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: import name type can only be used with link kind `raw-dylib`
--> $DIR/import-name-type-unsupported-link-kind.rs:10:39
|
LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors; 1 warning emitted

9 changes: 9 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// only-windows
// ignore-x86
#![feature(raw_dylib)]
//~^ WARN the feature `raw_dylib` is incomplete
#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
//~^ ERROR import name type is only supported on x86
extern "C" { }

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/import-name-type-x86-only.rs:3: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: import name type is only supported on x86
--> $DIR/import-name-type-x86-only.rs:5:42
|
LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted