]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/trans/base.rs
librustc: Allow linkage attribute on any statics, not just foreign statics.
[rust.git] / src / librustc / middle / trans / base.rs
index 0d8ef560c7d57c3f8fad5617eebf4b71224a340d..09fd3a38c1739d2381fbfed72f90102c5a9595a0 100644 (file)
@@ -32,7 +32,7 @@
 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 @@ fn visit_item(&mut self, i: &ast::Item) {
     }
 }
 
+pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
+    // 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);