diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 0d8ef560c7d5..09fd3a38c173 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -32,7 +32,7 @@ use driver::config::{NoDebugInfo, FullDebugInfo}; use driver::driver::{CrateAnalysis, CrateTranslation, ModuleTranslation}; use driver::session::Session; use lint; -use llvm::{BasicBlockRef, ValueRef, Vector, get_param}; +use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; @@ -2153,6 +2153,32 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TransItemVisitor<'a, 'tcx> { } } +pub fn llvm_linkage_by_name(name: &str) -> Option { + // Use the names from src/llvm/docs/LangRef.rst here. Most types are only + // applicable to variable declarations and may not really make sense for + // Rust code in the first place but whitelist them anyway and trust that + // the user knows what s/he's doing. Who knows, unanticipated use cases + // may pop up in the future. + // + // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported + // and don't have to be, LLVM treats them as no-ops. + match name { + "appending" => Some(llvm::AppendingLinkage), + "available_externally" => Some(llvm::AvailableExternallyLinkage), + "common" => Some(llvm::CommonLinkage), + "extern_weak" => Some(llvm::ExternalWeakLinkage), + "external" => Some(llvm::ExternalLinkage), + "internal" => Some(llvm::InternalLinkage), + "linkonce" => Some(llvm::LinkOnceAnyLinkage), + "linkonce_odr" => Some(llvm::LinkOnceODRLinkage), + "private" => Some(llvm::PrivateLinkage), + "weak" => Some(llvm::WeakAnyLinkage), + "weak_odr" => Some(llvm::WeakODRLinkage), + _ => None, + } +} + + /// Enum describing the origin of an LLVM `Value`, for linkage purposes. pub enum ValueOrigin { /// The LLVM `Value` is in this context because the corresponding item was @@ -2190,6 +2216,23 @@ pub fn update_linkage(ccx: &CrateContext, OriginalTranslation => {}, } + match id { + Some(id) => { + let item = ccx.tcx().map.get(id); + if let ast_map::NodeItem(i) = item { + if let Some(name) = attr::first_attr_value_str_by_name(i.attrs[], "linkage") { + if let Some(linkage) = llvm_linkage_by_name(name.get()) { + llvm::SetLinkage(llval, linkage); + } else { + ccx.sess().span_fatal(i.span, "invalid linkage specified"); + } + return; + } + } + } + _ => {} + } + match id { Some(id) if ccx.reachable().contains(&id) => { llvm::SetLinkage(llval, llvm::ExternalLinkage); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index bed45a286911..7aa201153704 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -10,10 +10,10 @@ use back::{link}; -use llvm::{ValueRef, CallConv, Linkage, get_param}; +use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; -use middle::trans::base::push_ctxt; +use middle::trans::base::{llvm_linkage_by_name, push_ctxt}; use middle::trans::base; use middle::trans::build::*; use middle::trans::cabi; @@ -101,31 +101,6 @@ pub fn llvm_calling_convention(ccx: &CrateContext, } } -pub fn llvm_linkage_by_name(name: &str) -> Option { - // Use the names from src/llvm/docs/LangRef.rst here. Most types are only - // applicable to variable declarations and may not really make sense for - // Rust code in the first place but whitelist them anyway and trust that - // the user knows what s/he's doing. Who knows, unanticipated use cases - // may pop up in the future. - // - // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported - // and don't have to be, LLVM treats them as no-ops. - match name { - "appending" => Some(llvm::AppendingLinkage), - "available_externally" => Some(llvm::AvailableExternallyLinkage), - "common" => Some(llvm::CommonLinkage), - "extern_weak" => Some(llvm::ExternalWeakLinkage), - "external" => Some(llvm::ExternalLinkage), - "internal" => Some(llvm::InternalLinkage), - "linkonce" => Some(llvm::LinkOnceAnyLinkage), - "linkonce_odr" => Some(llvm::LinkOnceODRLinkage), - "private" => Some(llvm::PrivateLinkage), - "weak" => Some(llvm::WeakAnyLinkage), - "weak_odr" => Some(llvm::WeakODRLinkage), - _ => None, - } -} - pub fn register_static(ccx: &CrateContext, foreign_item: &ast::ForeignItem) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c38fea9b3d58..98c49c002056 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -181,6 +181,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { "`#[thread_local]` is an experimental feature, and does not \ currently handle destructors. There is no corresponding \ `#[task_local]` mapping to the task model"); + } else if attr.name().equiv(&("linkage")) { + self.gate_feature("linkage", i.span, + "the `linkage` attribute is experimental \ + and not portable across platforms") } } match i.node {