diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 1e21d6aabe9..c2c23f6a032 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -187,8 +187,7 @@ pub trait CrateStore<'tcx> : Any { fn is_defaulted_trait(&self, did: DefId) -> bool; fn is_impl(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; - fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool; - fn is_static(&self, did: DefId) -> bool; + fn is_extern_item(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool; fn is_static_method(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; fn is_typedef(&self, did: DefId) -> bool; @@ -357,8 +356,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_defaulted_trait(&self, did: DefId) -> bool { unimplemented!() } fn is_impl(&self, did: DefId) -> bool { unimplemented!() } fn is_default_impl(&self, impl_did: DefId) -> bool { unimplemented!() } - fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool { unimplemented!() } - fn is_static(&self, did: DefId) -> bool { unimplemented!() } + fn is_extern_item(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool { unimplemented!() } fn is_static_method(&self, did: DefId) -> bool { unimplemented!() } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } fn is_typedef(&self, did: DefId) -> bool { unimplemented!() } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d34c3b74217..d2e1b3edc3a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -229,16 +229,18 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { fn propagate_node(&mut self, node: &ast_map::Node, search_item: ast::NodeId) { if !self.any_library { - // If we are building an executable, then there's no need to flag - // anything as external except for `extern fn` types. These - // functions may still participate in some form of native interface, - // but all other rust-only interfaces can be private (they will not - // participate in linkage after this product is produced) + // If we are building an executable, only explicitly extern + // types need to be exported. if let ast_map::NodeItem(item) = *node { - if let hir::ItemFn(_, _, _, abi, _, _) = item.node { - if abi != Abi::Rust { - self.reachable_symbols.insert(search_item); - } + let reachable = if let hir::ItemFn(_, _, _, abi, _, _) = item.node { + abi != Abi::Rust + } else { + false + }; + let is_extern = attr::contains_extern_indicator(&self.tcx.sess.diagnostic(), + &item.attrs); + if reachable || is_extern { + self.reachable_symbols.insert(search_item); } } } else { diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 06a2727ea28..5eade3bc0a5 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -260,16 +260,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_default_impl(&*cdata, impl_did.index) } - fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool - { + fn is_extern_item(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool { let cdata = self.get_crate_data(did.krate); - decoder::is_extern_fn(&*cdata, did.index, tcx) - } - - fn is_static(&self, did: DefId) -> bool - { - let cdata = self.get_crate_data(did.krate); - decoder::is_static(&*cdata, did.index) + decoder::is_extern_item(&*cdata, did.index, tcx) } fn is_static_method(&self, def: DefId) -> bool diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5ba9e566e00..8409a0c74b8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1567,11 +1567,29 @@ pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { } } -pub fn is_static(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { +pub fn is_extern_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool { + let item_doc = match cdata.get_item(id) { + Some(doc) => doc, + None => return false, + }; + let applicable = match item_family(item_doc) { ImmStatic | MutStatic => true, + Fn => { + let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); + let no_generics = generics.types.is_empty(); + match ty.sty { + ty::TyBareFn(_, fn_ty) if fn_ty.abi != Abi::Rust => return no_generics, + _ => no_generics, + } + }, _ => false, + }; + + if applicable { + attr::contains_extern_indicator(tcx.sess.diagnostic(), + &get_attributes(item_doc)) + } else { + false } } @@ -1693,22 +1711,6 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { }).collect() } -pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool { - let item_doc = match cdata.get_item(id) { - Some(doc) => doc, - None => return false, - }; - if let Fn = item_family(item_doc) { - let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); - generics.types.is_empty() && match ty.sty { - ty::TyBareFn(_, fn_ty) => fn_ty.abi != Abi::Rust, - _ => false, - } - } else { - false - } -} - pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { let closure_doc = cdata.lookup_item(closure_id); let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index c2d962b032f..4748c62921d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -3281,8 +3281,7 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>, for cnum in sess.cstore.crates() { let syms = sess.cstore.reachable_ids(cnum); reachable_symbols.extend(syms.into_iter().filter(|did| { - sess.cstore.is_extern_fn(shared_ccx.tcx(), *did) || - sess.cstore.is_static(*did) + sess.cstore.is_extern_item(shared_ccx.tcx(), *did) }).map(|did| { sess.cstore.item_symbol(did) })); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index cc5f30e2184..9953947eb52 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -316,6 +316,11 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option bool { + contains_name(attrs, "no_mangle") || + find_export_name_attr(diag, attrs).is_some() +} + #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None,