diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 09dec375a69a5..539b0fe694e59 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -344,9 +344,9 @@ pub fn is_const_fn(cstore: &cstore::CStore, did: DefId) -> bool { decoder::is_const_fn(&*cdata, did.index) } -pub fn is_static(cstore: &cstore::CStore, did: DefId) -> bool { +pub fn is_extern_item(cstore: &cstore::CStore, did: DefId, tcx: &ty::ctxt) -> bool { let cdata = cstore.get_crate_data(did.krate); - decoder::is_static(&*cdata, did.index) + decoder::is_extern_item(&*cdata, did.index, tcx) } pub fn is_impl(cstore: &cstore::CStore, did: DefId) -> bool { @@ -381,12 +381,6 @@ pub fn is_default_impl(cstore: &cstore::CStore, impl_did: DefId) -> bool { decoder::is_default_impl(&*cdata, impl_did.index) } -pub fn is_extern_fn(cstore: &cstore::CStore, did: DefId, - tcx: &ty::ctxt) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_extern_fn(&*cdata, did.index, tcx) -} - pub fn closure_kind<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); let cdata = tcx.sess.cstore.get_crate_data(def_id.krate); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b102213eff021..062e6e240d366 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1425,11 +1425,28 @@ 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(&get_attributes(item_doc)) + } else { + false } } @@ -1549,22 +1566,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/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7175fbe0e570d..92685da61311a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -235,16 +235,16 @@ 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 + }; + if reachable || attr::contains_extern_indicator(&item.attrs) { + self.reachable_symbols.insert(search_item); } } } else { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 4a99f2142d790..815cb9602980e 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2875,8 +2875,7 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>, sess.cstore.iter_crate_data(|cnum, _| { let syms = csearch::get_reachable_ids(&sess.cstore, cnum); reachable_symbols.extend(syms.into_iter().filter(|did| { - csearch::is_extern_fn(&sess.cstore, *did, shared_ccx.tcx()) || - csearch::is_static(&sess.cstore, *did) + csearch::is_extern_item(&sess.cstore, *did, shared_ccx.tcx()) }).map(|did| { csearch::get_symbol(&sess.cstore, did) })); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 571f950643792..b937b2f047bee 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -312,6 +312,15 @@ pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option< }) } +pub fn contains_extern_indicator(attrs: &[Attribute]) -> bool { + contains_name(attrs, "no_mangle") || + contains_name(attrs, "export_name") || + first_attr_value_str_by_name(attrs, "linkage").map(|v| match &*v { + "external" | "extern_weak" => true, + _ => false, + }).unwrap_or(false) +} + #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None,