From 0bcbe91b487ea933aba9a9e079f01133574fc98f Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 23 Jul 2018 08:43:22 -0400 Subject: [PATCH] Deduplicate linkage checking code for statics Signed-off-by: Gabriel Smith --- src/librustc_codegen_llvm/consts.rs | 154 +++++++++++++--------------- 1 file 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 +) -> 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,