Skip to content

Commit bc019df

Browse files
committed
Emit 'dllimport' attribute for dylib foreign items on Windows.
1 parent 908dba0 commit bc019df

File tree

11 files changed

+220
-46
lines changed

11 files changed

+220
-46
lines changed

src/librustc/middle/cstore.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ pub struct NativeLibrary {
131131
pub kind: NativeLibraryKind,
132132
pub name: Symbol,
133133
pub cfg: Option<ast::MetaItem>,
134+
pub foreign_items: Vec<DefIndex>,
134135
}
135136

136137
/// The data we save and restore about an inlined item or method. This is not
@@ -305,7 +306,8 @@ pub trait CrateStore<'tcx> {
305306
fn is_defaulted_trait(&self, did: DefId) -> bool;
306307
fn is_default_impl(&self, impl_did: DefId) -> bool;
307308
fn is_foreign_item(&self, did: DefId) -> bool;
308-
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool;
309+
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
310+
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool;
309311

310312
// crate metadata
311313
fn dylib_dependency_formats(&self, cnum: CrateNum)
@@ -462,7 +464,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
462464
fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
463465
fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
464466
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
465-
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false }
467+
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
468+
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false }
466469

467470
// crate metadata
468471
fn dylib_dependency_formats(&self, cnum: CrateNum)
@@ -526,9 +529,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
526529
// This is basically a 1-based range of ints, which is a little
527530
// silly - I may fix that.
528531
fn crates(&self) -> Vec<CrateNum> { vec![] }
529-
fn used_libraries(&self) -> Vec<NativeLibrary> {
530-
vec![]
531-
}
532+
fn used_libraries(&self) -> Vec<NativeLibrary> { vec![] }
532533
fn used_link_args(&self) -> Vec<String> { vec![] }
533534

534535
// utility functions

src/librustc_metadata/creader.rs

+53-25
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub struct CrateLoader<'a> {
5252
pub sess: &'a Session,
5353
cstore: &'a CStore,
5454
next_crate_num: CrateNum,
55-
foreign_item_map: FxHashMap<String, Vec<ast::NodeId>>,
55+
foreign_item_map: FxHashMap<String, Vec<DefIndex>>,
5656
local_crate_name: Symbol,
5757
}
5858

@@ -310,6 +310,7 @@ impl<'a> CrateLoader<'a> {
310310
rlib: rlib,
311311
rmeta: rmeta,
312312
},
313+
dllimport_foreign_items: RefCell::new(None),
313314
});
314315

315316
self.cstore.set_crate_data(cnum, cmeta.clone());
@@ -640,18 +641,36 @@ impl<'a> CrateLoader<'a> {
640641
}
641642
}
642643

643-
fn register_statically_included_foreign_items(&mut self) {
644+
fn get_foreign_items_of_kind(&self, kind: cstore::NativeLibraryKind) -> Vec<DefIndex> {
645+
let mut items = vec![];
644646
let libs = self.cstore.get_used_libraries();
647+
for lib in libs.borrow().iter() {
648+
if lib.kind == kind {
649+
items.extend(&lib.foreign_items);
650+
}
651+
}
645652
for (foreign_lib, list) in self.foreign_item_map.iter() {
646-
let is_static = libs.borrow().iter().any(|lib| {
647-
lib.name == &**foreign_lib && lib.kind == cstore::NativeStatic
653+
let kind_matches = libs.borrow().iter().any(|lib| {
654+
lib.name == &**foreign_lib && lib.kind == kind
648655
});
649-
if is_static {
650-
for id in list {
651-
self.cstore.add_statically_included_foreign_item(*id);
652-
}
656+
if kind_matches {
657+
items.extend(list)
653658
}
654659
}
660+
items
661+
}
662+
663+
fn register_statically_included_foreign_items(&mut self) {
664+
for id in self.get_foreign_items_of_kind(cstore::NativeStatic) {
665+
self.cstore.add_statically_included_foreign_item(id);
666+
}
667+
}
668+
669+
fn register_dllimport_foreign_items(&mut self) {
670+
let mut dllimports = self.cstore.dllimport_foreign_items.borrow_mut();
671+
for id in self.get_foreign_items_of_kind(cstore::NativeUnknown) {
672+
dllimports.insert(id);
673+
}
655674
}
656675

657676
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -861,7 +880,8 @@ impl<'a> CrateLoader<'a> {
861880
}
862881
}
863882

864-
fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) {
883+
fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod,
884+
definitions: &Definitions) {
865885
if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
866886
return;
867887
}
@@ -912,10 +932,14 @@ impl<'a> CrateLoader<'a> {
912932
let cfg = cfg.map(|list| {
913933
list[0].meta_item().unwrap().clone()
914934
});
935+
let foreign_items = fm.items.iter()
936+
.map(|it| definitions.opt_def_index(it.id).unwrap())
937+
.collect();
915938
let lib = NativeLibrary {
916939
name: n,
917940
kind: kind,
918941
cfg: cfg,
942+
foreign_items: foreign_items,
919943
};
920944
register_native_lib(self.sess, self.cstore, Some(m.span), lib);
921945
}
@@ -928,7 +952,7 @@ impl<'a> CrateLoader<'a> {
928952
};
929953
let list = self.foreign_item_map.entry(lib_name.to_string())
930954
.or_insert(Vec::new());
931-
list.extend(fm.items.iter().map(|it| it.id));
955+
list.extend(fm.items.iter().map(|it| definitions.opt_def_index(it.id).unwrap()));
932956
}
933957
}
934958
}
@@ -947,30 +971,34 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
947971
name: Symbol::intern(name),
948972
kind: kind,
949973
cfg: None,
974+
foreign_items: Vec::new(),
950975
};
951976
register_native_lib(self.sess, self.cstore, None, lib);
952977
}
953978
self.register_statically_included_foreign_items();
979+
self.register_dllimport_foreign_items();
954980
}
955981

956982
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
957983
match item.node {
958-
ast::ItemKind::ExternCrate(_) => {}
959-
ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
960-
_ => return,
961-
}
962-
963-
let info = self.extract_crate_info(item).unwrap();
964-
let (cnum, ..) = self.resolve_crate(
965-
&None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind,
966-
);
984+
ast::ItemKind::ForeignMod(ref fm) => {
985+
self.process_foreign_mod(item, fm, definitions)
986+
},
987+
ast::ItemKind::ExternCrate(_) => {
988+
let info = self.extract_crate_info(item).unwrap();
989+
let (cnum, ..) = self.resolve_crate(
990+
&None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind,
991+
);
967992

968-
let def_id = definitions.opt_local_def_id(item.id).unwrap();
969-
let len = definitions.def_path(def_id.index).data.len();
993+
let def_id = definitions.opt_local_def_id(item.id).unwrap();
994+
let len = definitions.def_path(def_id.index).data.len();
970995

971-
let extern_crate =
972-
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
973-
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
974-
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
996+
let extern_crate =
997+
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
998+
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
999+
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
1000+
}
1001+
_ => {}
1002+
}
9751003
}
9761004
}

src/librustc_metadata/cstore.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ use locator;
1515
use schema;
1616

1717
use rustc::dep_graph::DepGraph;
18-
use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
18+
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId};
1919
use rustc::hir::map::DefKey;
2020
use rustc::hir::svh::Svh;
2121
use rustc::middle::cstore::{DepKind, ExternCrate};
2222
use rustc_back::PanicStrategy;
2323
use rustc_data_structures::indexed_vec::IndexVec;
24-
use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap};
24+
use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap, DefIdMap};
2525

2626
use std::cell::{RefCell, Cell};
2727
use std::rc::Rc;
@@ -31,7 +31,7 @@ use syntax::ext::base::SyntaxExtension;
3131
use syntax::symbol::Symbol;
3232
use syntax_pos;
3333

34-
pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference};
34+
pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
3535
pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
3636
pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
3737

@@ -84,6 +84,8 @@ pub struct CrateMetadata {
8484
pub source: CrateSource,
8585

8686
pub proc_macros: Option<Vec<(ast::Name, Rc<SyntaxExtension>)>>,
87+
// Foreign items imported from a dylib (Windows only)
88+
pub dllimport_foreign_items: RefCell<Option<FxHashSet<DefIndex>>>,
8789
}
8890

8991
pub struct CachedInlinedItem {
@@ -100,7 +102,8 @@ pub struct CStore {
100102
extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
101103
used_libraries: RefCell<Vec<NativeLibrary>>,
102104
used_link_args: RefCell<Vec<String>>,
103-
statically_included_foreign_items: RefCell<NodeSet>,
105+
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
106+
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
104107
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
105108
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
106109
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
@@ -114,7 +117,8 @@ impl CStore {
114117
extern_mod_crate_map: RefCell::new(FxHashMap()),
115118
used_libraries: RefCell::new(Vec::new()),
116119
used_link_args: RefCell::new(Vec::new()),
117-
statically_included_foreign_items: RefCell::new(NodeSet()),
120+
statically_included_foreign_items: RefCell::new(FxHashSet()),
121+
dllimport_foreign_items: RefCell::new(FxHashSet()),
118122
visible_parent_map: RefCell::new(FxHashMap()),
119123
inlined_item_cache: RefCell::new(FxHashMap()),
120124
defid_for_inlined_node: RefCell::new(FxHashMap()),
@@ -246,12 +250,13 @@ impl CStore {
246250
self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
247251
}
248252

249-
pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) {
253+
pub fn add_statically_included_foreign_item(&self, id: DefIndex) {
250254
self.statically_included_foreign_items.borrow_mut().insert(id);
251255
}
252256

253-
pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool {
254-
self.statically_included_foreign_items.borrow().contains(&id)
257+
pub fn do_is_statically_included_foreign_item(&self, def_id: DefId) -> bool {
258+
assert!(def_id.krate == LOCAL_CRATE);
259+
self.statically_included_foreign_items.borrow().contains(&def_id.index)
255260
}
256261

257262
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {

src/librustc_metadata/cstore_impl.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc::hir::def::{self, Def};
1919
use rustc::middle::lang_items;
2020
use rustc::session::Session;
2121
use rustc::ty::{self, Ty, TyCtxt};
22-
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
22+
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
2323

2424
use rustc::dep_graph::DepNode;
2525
use rustc::hir::map as hir_map;
@@ -217,9 +217,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
217217
self.get_crate_data(did.krate).is_foreign_item(did.index)
218218
}
219219

220-
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool
220+
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool
221221
{
222-
self.do_is_statically_included_foreign_item(id)
222+
self.do_is_statically_included_foreign_item(def_id)
223+
}
224+
225+
fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool {
226+
if def_id.krate == LOCAL_CRATE {
227+
self.dllimport_foreign_items.borrow().contains(&def_id.index)
228+
} else {
229+
self.get_crate_data(def_id.krate).is_dllimport_foreign_item(def_id.index)
230+
}
223231
}
224232

225233
fn dylib_dependency_formats(&self, cnum: CrateNum)

src/librustc_metadata/decoder.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
// Decoding metadata from a single crate's metadata
1212

1313
use astencode::decode_inlined_item;
14-
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
14+
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, NativeLibraryKind};
1515
use index::Index;
1616
use schema::*;
1717

1818
use rustc::hir::map as hir_map;
1919
use rustc::hir::map::{DefKey, DefPathData};
20-
use rustc::util::nodemap::FxHashMap;
20+
use rustc::util::nodemap::{FxHashMap, FxHashSet};
2121
use rustc::hir;
2222
use rustc::hir::intravisit::IdRange;
2323

@@ -36,6 +36,7 @@ use rustc::mir::Mir;
3636
use std::borrow::Cow;
3737
use std::cell::Ref;
3838
use std::io;
39+
use std::iter::FromIterator;
3940
use std::mem;
4041
use std::str;
4142
use std::u32;
@@ -1087,6 +1088,18 @@ impl<'a, 'tcx> CrateMetadata {
10871088
}
10881089
}
10891090

1091+
pub fn is_dllimport_foreign_item(&self, id: DefIndex) -> bool {
1092+
if self.dllimport_foreign_items.borrow().is_none() {
1093+
*self.dllimport_foreign_items.borrow_mut() = Some(FxHashSet::from_iter(
1094+
self.get_native_libraries().iter()
1095+
.filter(|lib| lib.kind == NativeLibraryKind::NativeUnknown)
1096+
.flat_map(|lib| &lib.foreign_items)
1097+
.map(|id| *id)
1098+
));
1099+
}
1100+
self.dllimport_foreign_items.borrow().as_ref().unwrap().contains(&id)
1101+
}
1102+
10901103
pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
10911104
match self.entry(trait_id).kind {
10921105
EntryKind::Trait(data) => data.decode(self).has_default_impl,

src/librustc_trans/base.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
14981498
// let it through if it's included statically.
14991499
match tcx.map.get(id) {
15001500
hir_map::NodeForeignItem(..) => {
1501-
tcx.sess.cstore.is_statically_included_foreign_item(id)
1501+
let def_id = tcx.map.local_def_id(id);
1502+
tcx.sess.cstore.is_statically_included_foreign_item(def_id)
15021503
}
15031504

15041505
// Only consider nodes that actually have exported symbols.

src/librustc_trans/callee.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,11 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
629629
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
630630
}
631631
}
632-
632+
if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) {
633+
unsafe {
634+
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
635+
}
636+
}
633637
llfn
634638
};
635639

src/librustc_trans/consts.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,25 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
191191
llvm::set_thread_local(g, true);
192192
}
193193
}
194-
if ccx.use_dll_storage_attrs() {
194+
if ccx.use_dll_storage_attrs() && !ccx.sess().cstore.is_foreign_item(def_id) {
195+
// This item is external but not foreign, i.e. it originates from an external Rust
196+
// crate. Since we don't know whether this crate will be linked dynamically or
197+
// statically in the final application, we always mark such symbols as 'dllimport'.
198+
// If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to
199+
// make things work.
195200
unsafe {
196201
llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
197202
}
198203
}
199204
g
200205
};
201206

207+
if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) {
208+
// For foreign (native) libs we know the exact storage type to use.
209+
unsafe {
210+
llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
211+
}
212+
}
202213
ccx.instances().borrow_mut().insert(instance, g);
203214
ccx.statics().borrow_mut().insert(g, def_id);
204215
g
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
#![crate_type = "staticlib"]
13+
14+
// Since codegen tests don't actually perform linking, this library doesn't need to export
15+
// any symbols. It's here just to satisfy the compiler looking for a .lib file when processing
16+
// #[link(...)] attributes in wrapper.rs.

0 commit comments

Comments
 (0)