about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGabriel Smith <ga29smith@gmail.com>2018-07-23 08:43:22 -0400
committerGabriel Smith <ga29smith@gmail.com>2018-07-24 20:17:14 -0400
commit0bcbe91b487ea933aba9a9e079f01133574fc98f (patch)
treef9a9b7cbda613d4be488eb795158b145191f69e9
parenta20262c06986acb98150913e2c43cb13cead92a7 (diff)
downloadrust-0bcbe91b487ea933aba9a9e079f01133574fc98f.tar.gz
rust-0bcbe91b487ea933aba9a9e079f01133574fc98f.zip
Deduplicate linkage checking code for statics
Signed-off-by: Gabriel Smith <ga29smith@gmail.com>
-rw-r--r--src/librustc_codegen_llvm/consts.rs154
1 files changed, 69 insertions, 85 deletions
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 1d42c84e2be..f0b5f4b8879 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -20,12 +20,14 @@ use monomorphize::MonoItem;
 use common::{CodegenCx, val_ty};
 use declare;
 use monomorphize::Instance;
+use syntax_pos::Span;
+use syntax_pos::symbol::LocalInternedString;
 use type_::Type;
 use type_of::LayoutLlvmExt;
-use rustc::ty;
+use rustc::ty::{self, Ty};
 use rustc::ty::layout::{Align, LayoutOf};
 
-use rustc::hir::{self, CodegenFnAttrFlags};
+use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
 
 use std::ffi::{CStr, CString};
 
@@ -146,47 +148,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
             hir_map::NodeForeignItem(&hir::ForeignItem {
                 ref attrs, span, node: hir::ForeignItemKind::Static(..), ..
             }) => {
-                let g = if let Some(linkage) = cx.tcx.codegen_fn_attrs(def_id).linkage {
-                    debug!("get_static: sym={} linkage={:?}", sym, linkage);
-
-                    // If this is a static with a linkage specified, then we need to handle
-                    // it a little specially. The typesystem prevents things like &T and
-                    // extern "C" fn() from being non-null, so we can't just declare a
-                    // static and call it a day. Some linkages (like weak) will make it such
-                    // that the static actually has a null value.
-                    let llty2 = match ty.sty {
-                        ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
-                        _ => {
-                            cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`");
-                        }
-                    };
-                    unsafe {
-                        // Declare a symbol `foo` with the desired linkage.
-                        let g1 = declare::declare_global(cx, &sym, llty2);
-                        llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
-
-                        // Declare an internal global `extern_with_linkage_foo` which
-                        // is initialized with the address of `foo`.  If `foo` is
-                        // discarded during linking (for example, if `foo` has weak
-                        // linkage and there are no definitions), then
-                        // `extern_with_linkage_foo` will instead be initialized to
-                        // zero.
-                        let mut real_name = "_rust_extern_with_linkage_".to_string();
-                        real_name.push_str(&sym);
-                        let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
-                            cx.sess().span_fatal(span,
-                                &format!("symbol `{}` is already defined", &sym))
-                        });
-                        llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-                        llvm::LLVMSetInitializer(g2, g1);
-                        g2
-                    }
-                } else {
-                    // Generate an external declaration.
-                    declare::declare_global(cx, &sym, llty)
-                };
-
-                (g, attrs)
+                let fn_attrs = cx.tcx.codegen_fn_attrs(def_id);
+                (check_and_apply_linkage(cx, &fn_attrs, ty, sym, Some(span)), attrs)
             }
 
             item => bug!("get_static: expected static, found {:?}", item)
@@ -205,47 +168,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
         // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
         debug!("get_static: sym={} item_attr={:?}", sym, cx.tcx.item_attrs(def_id));
 
-        let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(def_id);
-        let llty = cx.layout_of(ty).llvm_type(cx);
-        let g = if let Some(linkage) = codegen_fn_attrs.linkage {
-            debug!("get_static: sym={} linkage={:?}", sym, linkage);
-
-            // If this is a static with a linkage specified, then we need to handle
-            // it a little specially. The typesystem prevents things like &T and
-            // extern "C" fn() from being non-null, so we can't just declare a
-            // static and call it a day. Some linkages (like weak) will make it such
-            // that the static actually has a null value.
-            let llty2 = match ty.sty {
-                ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
-                _ => {
-                    bug!("must have type `*const T` or `*mut T`")
-                }
-            };
-            unsafe {
-                // Declare a symbol `foo` with the desired linkage.
-                let g1 = declare::declare_global(cx, &sym, llty2);
-                llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
-
-                // Declare an internal global `extern_with_linkage_foo` which
-                // is initialized with the address of `foo`.  If `foo` is
-                // discarded during linking (for example, if `foo` has weak
-                // linkage and there are no definitions), then
-                // `extern_with_linkage_foo` will instead be initialized to
-                // zero.
-                let mut real_name = "_rust_extern_with_linkage_".to_string();
-                real_name.push_str(&sym);
-                let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
-                    bug!("symbol `{}` is already defined", &sym)
-                });
-                llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-                llvm::LLVMSetInitializer(g2, g1);
-                g2
-            }
-        } else {
-            // Generate an external declaration.
-            // FIXME(nagisa): investigate whether it can be changed into define_global
-            declare::declare_global(cx, &sym, llty)
-        };
+        let attrs = cx.tcx.codegen_fn_attrs(def_id);
+        let g = check_and_apply_linkage(cx, &attrs, ty, sym, None);
 
         // Thread-local statics in some other crate need to *always* be linked
         // against in a thread-local fashion, so we need to be sure to apply the
@@ -253,7 +177,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
         // don't do this then linker errors can be generated where the linker
         // complains that one object files has a thread local version of the
         // symbol and another one doesn't.
-        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
             llvm::set_thread_local_mode(g, cx.tls_model);
         }
 
@@ -289,6 +213,66 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
     g
 }
 
+fn check_and_apply_linkage<'tcx>(
+    cx: &CodegenCx<'_, 'tcx>,
+    attrs: &CodegenFnAttrs,
+    ty: Ty<'tcx>,
+    sym: LocalInternedString,
+    span: Option<Span>
+) -> ValueRef {
+    let llty = cx.layout_of(ty).llvm_type(cx);
+    if let Some(linkage) = attrs.linkage {
+        debug!("get_static: sym={} linkage={:?}", sym, linkage);
+
+        // If this is a static with a linkage specified, then we need to handle
+        // it a little specially. The typesystem prevents things like &T and
+        // extern "C" fn() from being non-null, so we can't just declare a
+        // static and call it a day. Some linkages (like weak) will make it such
+        // that the static actually has a null value.
+        let llty2 = match ty.sty {
+            ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
+            _ => {
+                if span.is_some() {
+                    cx.sess().span_fatal(span.unwrap(), "must have type `*const T` or `*mut T`")
+                } else {
+                    bug!("must have type `*const T` or `*mut T`")
+                }
+            }
+        };
+        unsafe {
+            // Declare a symbol `foo` with the desired linkage.
+            let g1 = declare::declare_global(cx, &sym, llty2);
+            llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
+
+            // Declare an internal global `extern_with_linkage_foo` which
+            // is initialized with the address of `foo`.  If `foo` is
+            // discarded during linking (for example, if `foo` has weak
+            // linkage and there are no definitions), then
+            // `extern_with_linkage_foo` will instead be initialized to
+            // zero.
+            let mut real_name = "_rust_extern_with_linkage_".to_string();
+            real_name.push_str(&sym);
+            let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
+                if span.is_some() {
+                    cx.sess().span_fatal(
+                        span.unwrap(),
+                        &format!("symbol `{}` is already defined", &sym)
+                    )
+                } else {
+                    bug!("symbol `{}` is already defined", &sym)
+                }
+            });
+            llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
+            llvm::LLVMSetInitializer(g2, g1);
+            g2
+        }
+    } else {
+        // Generate an external declaration.
+        // FIXME(nagisa): investigate whether it can be changed into define_global
+        declare::declare_global(cx, &sym, llty)
+    }
+}
+
 pub fn codegen_static<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     def_id: DefId,