From 27ea11eda820a8bb5b552c4fb37668bcec2df914 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Nov 2014 20:22:41 -0500 Subject: [PATCH 1/4] librustc: Allow linkage attribute on any statics, not just foreign statics. --- src/librustc/middle/trans/base.rs | 45 +++++++++++++++++++++++++++- src/librustc/middle/trans/foreign.rs | 29 ++---------------- src/libsyntax/feature_gate.rs | 4 +++ 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 0d8ef560c7d..09fd3a38c17 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 bed45a28691..7aa20115370 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 c38fea9b3d5..98c49c00205 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 { From 04a02ffb94314a842a87142042175822d60e58b4 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Nov 2014 20:23:32 -0500 Subject: [PATCH 2/4] librustc: Respect no-compiler-rt target option for static libs as well. --- src/librustc/back/link.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 3f76a575a1e..e72c6fcd4df 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -728,7 +728,9 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) { if sess.target.target.options.morestack { ab.add_native_library("morestack").unwrap(); } - ab.add_native_library("compiler-rt").unwrap(); + if !sess.target.target.options.no_compiler_rt { + ab.add_native_library("compiler-rt").unwrap(); + } let crates = sess.cstore.get_used_crates(cstore::RequireStatic); let mut all_native_libs = vec![]; From acd890d96da88d93a2fd0c9b8e37ed111b17a62f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Nov 2014 21:34:18 -0500 Subject: [PATCH 3/4] Add tests. --- src/test/compile-fail/linkage4.rs | 15 +++++++++++ .../run-make/linkage-attr-on-static/Makefile | 8 ++++++ .../run-make/linkage-attr-on-static/bar.rs | 25 +++++++++++++++++++ .../run-make/linkage-attr-on-static/foo.c | 7 ++++++ 4 files changed, 55 insertions(+) create mode 100644 src/test/compile-fail/linkage4.rs create mode 100644 src/test/run-make/linkage-attr-on-static/Makefile create mode 100644 src/test/run-make/linkage-attr-on-static/bar.rs create mode 100644 src/test/run-make/linkage-attr-on-static/foo.c diff --git a/src/test/compile-fail/linkage4.rs b/src/test/compile-fail/linkage4.rs new file mode 100644 index 00000000000..8f68f3e553c --- /dev/null +++ b/src/test/compile-fail/linkage4.rs @@ -0,0 +1,15 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[linkage = "external"] +static foo: int = 0; +//~^ ERROR: the `linkage` attribute is experimental and not portable + +fn main() {} diff --git a/src/test/run-make/linkage-attr-on-static/Makefile b/src/test/run-make/linkage-attr-on-static/Makefile new file mode 100644 index 00000000000..6bcde96335c --- /dev/null +++ b/src/test/run-make/linkage-attr-on-static/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: + $(CC) foo.c -c -o $(TMPDIR)/foo.o + $(AR) rcs $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o + $(RUSTC) bar.rs -lfoo -L $(TMPDIR) + $(call RUN,bar) || exit 1 + diff --git a/src/test/run-make/linkage-attr-on-static/bar.rs b/src/test/run-make/linkage-attr-on-static/bar.rs new file mode 100644 index 00000000000..6125421bdeb --- /dev/null +++ b/src/test/run-make/linkage-attr-on-static/bar.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(linkage)] + +#[no_mangle] +#[linkage = "external"] +static BAZ: i32 = 21; + +extern { + fn what() -> i32; +} + +fn main() { + unsafe { + assert_eq!(what(), BAZ); + } +} diff --git a/src/test/run-make/linkage-attr-on-static/foo.c b/src/test/run-make/linkage-attr-on-static/foo.c new file mode 100644 index 00000000000..78a6934f57f --- /dev/null +++ b/src/test/run-make/linkage-attr-on-static/foo.c @@ -0,0 +1,7 @@ +#include + +extern int32_t BAZ; + +int32_t what() { + return BAZ; +} From 33893aebcf19f6bf7e0102406117afa34a955425 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 11 Nov 2014 21:46:45 -0500 Subject: [PATCH 4/4] librustc: Whitelist linkage attribute for unused attribute lint since it's processed during trans. --- src/librustc/lint/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 3026e047626..9f394cb4c7a 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -619,6 +619,7 @@ impl LintPass for UnusedAttributes { "link", "link_name", "link_section", + "linkage", "no_builtins", "no_mangle", "no_split_stack",