From b9a11f0f85416924487e17601458eb07b2e9fa06 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Feb 2015 13:32:12 +0200 Subject: [PATCH 01/14] Fix a broken test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It emits the same symbol – `transmute` – from the same crate twice. --- src/test/run-pass/issue-15562.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/run-pass/issue-15562.rs b/src/test/run-pass/issue-15562.rs index f1ef57e44b1d5..da1e15d826d99 100644 --- a/src/test/run-pass/issue-15562.rs +++ b/src/test/run-pass/issue-15562.rs @@ -15,9 +15,6 @@ extern crate issue_15562 as i; pub fn main() { - extern { - fn transmute(); - } unsafe { transmute(); i::transmute(); From 723ca4bd4dd68a351dbd001ed1ae958e13c4bc8c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Feb 2015 13:34:33 +0200 Subject: [PATCH 02/14] Validate export_name attribute --- src/librustc_trans/trans/base.rs | 12 +++++------- src/libsyntax/attr.rs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 05c366a645e76..321cd33bbeb2f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1692,9 +1692,9 @@ pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, } } -// trans_closure: Builds an LLVM function out of a source function. -// If the function closes over its environment a closure will be -// returned. +/// Builds an LLVM function out of a source function. +/// +/// If the function closes over its environment a closure will be returned. pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -1827,8 +1827,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, finish_fn(&fcx, bcx, output_type, ret_debug_loc); } -// trans_fn: creates an LLVM function corresponding to a source language -// function. +/// Creates an LLVM function corresponding to a source language function. pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -2645,10 +2644,9 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, None => {} } - match attr::first_attr_value_str_by_name(attrs, "export_name") { + match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { // Use provided name Some(name) => name.to_string(), - _ => ccx.tcx().map.with_path(id, |path| { if attr::contains_name(attrs, "no_mangle") { // Don't mangle diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 06e447bb12af4..b966fe2c6e5cd 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -282,6 +282,23 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } +/// Find the value of #[export_name=*] attribute and check its validity. +pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option { + attrs.iter().fold(None, |ia,attr| { + if attr.check_name("export_name") { + if let s@Some(_) = attr.value_str() { + s + } else { + diag.span_err(attr.span, "export_name attribute has invalid format"); + diag.handler.help("use #[export_name=\"*\"]"); + None + } + } else { + ia + } + }) +} + #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, From 2198969f89e0b646794bb4259cefacf50d98fc16 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Feb 2015 13:37:33 +0200 Subject: [PATCH 03/14] =?UTF-8?q?Wrap=20LLVM=E2=80=99s=20Module::getNamedV?= =?UTF-8?q?alue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc_llvm/lib.rs | 1 + src/rustllvm/RustWrapper.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 9b0ae2e9ef858..ae4687eac2fac 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -924,6 +924,7 @@ extern { pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); + pub fn LLVMGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; /* Operations on aliases */ pub fn LLVMAddAlias(M: ModuleRef, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 9a87c03f1c407..ccdc3566c0935 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -77,6 +77,11 @@ extern "C" void LLVMRustPrintPassTimings() { TimerGroup::printAll(OS); } +extern "C" LLVMValueRef LLVMGetNamedValue(LLVMModuleRef M, + const char* Name) { + return wrap(unwrap(M)->getNamedValue(Name)); +} + extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, const char* Name, LLVMTypeRef FunctionTy) { From baa52caf83ef82c301e1264f370de5c22fc3c48d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Feb 2015 14:18:39 +0200 Subject: [PATCH 04/14] Abort creating wrapper fn for multiple inner fns This discovers another class of mis-trans where we wrap multiple native functions into a single wrapper, which is wrong. --- src/librustc_trans/trans/foreign.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e87a5865df054..e154bc1d579ff 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -642,6 +642,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } + if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 { + ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \ + multiple functions being wrapped"); + } + let ptr = "the block\0".as_ptr(); let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, ptr as *const _); From d36c4db96d117f4a45d3a7a0d3ba68fe8b6ee993 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Feb 2015 17:13:30 +0200 Subject: [PATCH 05/14] Add the tests for duplicate symbol errors --- src/test/compile-fail/dupe-symbols-1.rs | 21 +++++++++++++++++ src/test/compile-fail/dupe-symbols-2.rs | 25 ++++++++++++++++++++ src/test/compile-fail/dupe-symbols-3.rs | 21 +++++++++++++++++ src/test/compile-fail/dupe-symbols-4.rs | 31 +++++++++++++++++++++++++ src/test/compile-fail/dupe-symbols-5.rs | 20 ++++++++++++++++ src/test/compile-fail/dupe-symbols-6.rs | 18 ++++++++++++++ src/test/compile-fail/dupe-symbols-7.rs | 21 +++++++++++++++++ src/test/compile-fail/dupe-symbols-8.rs | 15 ++++++++++++ 8 files changed, 172 insertions(+) create mode 100644 src/test/compile-fail/dupe-symbols-1.rs create mode 100644 src/test/compile-fail/dupe-symbols-2.rs create mode 100644 src/test/compile-fail/dupe-symbols-3.rs create mode 100644 src/test/compile-fail/dupe-symbols-4.rs create mode 100644 src/test/compile-fail/dupe-symbols-5.rs create mode 100644 src/test/compile-fail/dupe-symbols-6.rs create mode 100644 src/test/compile-fail/dupe-symbols-7.rs create mode 100644 src/test/compile-fail/dupe-symbols-8.rs diff --git a/src/test/compile-fail/dupe-symbols-1.rs b/src/test/compile-fail/dupe-symbols-1.rs new file mode 100644 index 0000000000000..08370b534cdf1 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-1.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` already exists +} diff --git a/src/test/compile-fail/dupe-symbols-2.rs b/src/test/compile-fail/dupe-symbols-2.rs new file mode 100644 index 0000000000000..592874491e015 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +mod a { + #[no_mangle] + pub extern fn fail() { + } +} + +mod b { + #[no_mangle] + pub extern fn fail() { + //~^ symbol `fail` already exists + } +} diff --git a/src/test/compile-fail/dupe-symbols-3.rs b/src/test/compile-fail/dupe-symbols-3.rs new file mode 100644 index 0000000000000..af5622861ef71 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-3.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[no_mangle] +pub fn fail() { +//~^ symbol `fail` already exists +} diff --git a/src/test/compile-fail/dupe-symbols-4.rs b/src/test/compile-fail/dupe-symbols-4.rs new file mode 100644 index 0000000000000..738dce6fed1a3 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -0,0 +1,31 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + + +pub trait A { + fn fail(self); +} + +struct B; +struct C; + +impl A for B { + #[no_mangle] + fn fail(self) {} +} + +impl A for C { + #[no_mangle] + fn fail(self) {} + //~^ symbol `fail` already exists +} diff --git a/src/test/compile-fail/dupe-symbols-5.rs b/src/test/compile-fail/dupe-symbols-5.rs new file mode 100644 index 0000000000000..5ca9ca871289e --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-5.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` already exists +} diff --git a/src/test/compile-fail/dupe-symbols-6.rs b/src/test/compile-fail/dupe-symbols-6.rs new file mode 100644 index 0000000000000..9fbc292930ecb --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-6.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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. +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +static HELLO_TWICE: u16 = 0; +//~^ symbol `fail` already exists diff --git a/src/test/compile-fail/dupe-symbols-7.rs b/src/test/compile-fail/dupe-symbols-7.rs new file mode 100644 index 0000000000000..b061f9e257e7d --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-7.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +extern { + fn fail(); +} + +#[export_name="fail"] +pub fn a() { +//~^ symbol `fail` already exists +} diff --git a/src/test/compile-fail/dupe-symbols-8.rs b/src/test/compile-fail/dupe-symbols-8.rs new file mode 100644 index 0000000000000..c2880ba6f51e9 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-8.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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. +// +// error-pattern: entry symbol `main` defined multiple times +#![allow(warnings)] + +#[no_mangle] +fn main(){} From c71970eea2954b40b2b9f195507bc56d2507c5ac Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 28 Feb 2015 23:53:12 +0200 Subject: [PATCH 06/14] Extract attribute handling code into a module This commit causes no change in trans semantics, it just moves some functions around and deduplicates them. --- src/librustc_llvm/lib.rs | 3 +- src/librustc_trans/trans/attributes.rs | 108 ++++++++++++++++++++ src/librustc_trans/trans/base.rs | 125 +++++------------------ src/librustc_trans/trans/closure.rs | 3 +- src/librustc_trans/trans/foreign.rs | 3 +- src/librustc_trans/trans/mod.rs | 53 +++++----- src/librustc_trans/trans/monomorphize.rs | 8 +- 7 files changed, 172 insertions(+), 131 deletions(-) create mode 100644 src/librustc_trans/trans/attributes.rs diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index ae4687eac2fac..3eaa354c5e6da 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -157,7 +157,7 @@ bitflags! { #[derive(Copy, Clone)] pub enum OtherAttribute { // The following are not really exposed in - // the LLVM c api so instead to add these + // the LLVM C api so instead to add these // we call a wrapper function in RustWrapper // that uses the C++ api. SanitizeAddressAttribute = 1 << 32, @@ -958,6 +958,7 @@ extern { pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); /* Operations on parameters */ pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs new file mode 100644 index 0000000000000..76034420e4b97 --- /dev/null +++ b/src/librustc_trans/trans/attributes.rs @@ -0,0 +1,108 @@ +// Copyright 2012-2015 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. +//! Set and unset common attributes on LLVM values. + +use llvm::{self, ValueRef, AttrHelper}; +use syntax::ast; +use syntax::attr::InlineAttr; +pub use syntax::attr::InlineAttr::*; +use trans::context::CrateContext; + +use libc::{c_uint, c_ulonglong}; + +/// Mark LLVM function to use split stack. +#[inline] +pub fn split_stack(val: ValueRef, set: bool) { + unsafe { + let attr = "split-stack\0".as_ptr() as *const _; + if set { + llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } else { + llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } + } +} + +/// Mark LLVM function to use provided inline heuristic. +#[inline] +pub fn inline(val: ValueRef, inline: InlineAttr) { + match inline { + InlineHint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), + InlineAlways => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), + InlineNever => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), + InlineNone => { + let attr = llvm::InlineHintAttribute | + llvm::AlwaysInlineAttribute | + llvm::NoInlineAttribute; + unsafe { + llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong) + } + }, + }; +} + +/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. +#[inline] +pub fn emit_uwtable(val: ValueRef, emit: bool) { + if emit { + llvm::SetFunctionAttribute(val, llvm::UWTableAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong); + } + } +} + +/// Tell LLVM whether the function can or cannot unwind. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn unwind(val: ValueRef, can_unwind: bool) { + if can_unwind { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong); + } + } else { + llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute); + } +} + +/// Tell LLVM whether it should optimise function for size. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { + if optimize { + llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong); + } + } +} + +/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) +/// attributes. +pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { + use syntax::attr::*; + inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + + for attr in attrs { + if attr.check_name("no_stack_check") { + split_stack(llfn, false); + } else if attr.check_name("cold") { + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + llvm::FunctionIndex as c_uint, + llvm::ColdAttribute as u64) + } + } else if attr.check_name("allocator") { + llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } + } +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 321cd33bbeb2f..25750b6ec0e14 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,21 +7,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - -// trans.rs: Translate the completed AST to the LLVM IR. -// -// Some functions here, such as trans_block and trans_expr, return a value -- -// the result of the translation to LLVM -- while others, such as trans_fn, -// trans_impl, and trans_item, are called only for the side effect of adding a -// particular definition to the LLVM IR output we're producing. -// -// Hopefully useful general knowledge about trans: -// -// * There's no way to find out the Ty type of a ValueRef. Doing so -// would be "trying to get the eggs out of an omelette" (credit: -// pcwalton). You can, instead, find out its TypeRef by calling val_ty, -// but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, -// int) and rec(x=int, y=int, z=int) will have the same TypeRef. +//! Translate the completed AST to the LLVM IR. +//! +//! Some functions here, such as trans_block and trans_expr, return a value -- +//! the result of the translation to LLVM -- while others, such as trans_fn, +//! trans_impl, and trans_item, are called only for the side effect of adding a +//! particular definition to the LLVM IR output we're producing. +//! +//! Hopefully useful general knowledge about trans: +//! +//! * There's no way to find out the Ty type of a ValueRef. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, +//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, +//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. #![allow(non_camel_case_types)] @@ -33,7 +32,7 @@ use super::ModuleTranslation; use back::link::mangle_exported_name; use back::{link, abi}; use lint; -use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; @@ -46,6 +45,7 @@ use session::config::{self, NoDebugInfo}; use session::Session; use trans::_match; use trans::adt; +use trans::attributes; use trans::build::*; use trans::builder::{Builder, noname}; use trans::callee; @@ -204,7 +204,7 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::SetUnnamedAddr(llfn, true); if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { - set_split_stack(llfn); + attributes::split_stack(llfn, true); } llfn @@ -245,7 +245,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, let f = decl_rust_fn(ccx, fn_ty, name); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs[..], f); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs[..], f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -390,77 +390,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } -#[allow(dead_code)] // useful -pub fn set_optimize_for_size(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::OptimizeForSizeAttribute) -} - -pub fn set_no_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute) -} - -#[allow(dead_code)] // useful -pub fn set_no_unwind(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute) -} - -// Tell LLVM to emit the information necessary to unwind the stack for the -// function f. -pub fn set_uwtable(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::UWTableAttribute) -} - -pub fn set_inline_hint(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute) -} - -pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { - use syntax::attr::{find_inline_attr, InlineAttr}; - // Set the inline hint if there is one - match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) { - InlineAttr::Hint => set_inline_hint(llfn), - InlineAttr::Always => set_always_inline(llfn), - InlineAttr::Never => set_no_inline(llfn), - InlineAttr::None => { /* fallthrough */ } - } - - for attr in attrs { - let mut used = true; - match &attr.name()[..] { - "no_stack_check" => unset_split_stack(llfn), - "cold" => unsafe { - llvm::LLVMAddFunctionAttribute(llfn, - llvm::FunctionIndex as c_uint, - llvm::ColdAttribute as uint64_t) - }, - "allocator" => { - llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } -} - -pub fn set_always_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::AlwaysInlineAttribute) -} - -pub fn set_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -pub fn unset_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} // Double-check that we never ask LLVM to declare the same symbol twice. It // silently mangles such symbols, breaking our linkage model. @@ -898,7 +827,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => { let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); llfn } } @@ -1708,7 +1637,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); let _icx = push_ctxt("trans_closure"); - set_uwtable(llfndecl); + attributes::emit_uwtable(llfndecl, true); debug!("trans_closure(..., param_substs={})", param_substs.repr(ccx.tcx())); @@ -2312,7 +2241,7 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N // eh_personality functions need to be externally linkable. let def = ast_util::local_def(node_id); if ccx.tcx().lang_items.stack_exhausted() == Some(def) { - unset_split_stack(llfn); + attributes::split_stack(llfn, false); llvm::SetLinkage(llfn, llvm::ExternalLinkage); } if ccx.tcx().lang_items.eh_personality() == Some(def) { @@ -2733,7 +2662,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sym, i.id) }; - set_llvm_fn_attrs(ccx, &i.attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &i.attrs, llfn); llfn } @@ -2794,7 +2723,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - set_llvm_fn_attrs(ccx, &ni.attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &ni.attrs, llfn); llfn } ast::ForeignItemStatic(..) => { @@ -2826,7 +2755,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); llfn } @@ -2848,7 +2777,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); llfn } @@ -2883,7 +2812,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, } else { foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) }; - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); return llfn; } else { ccx.sess().span_bug(span, "expected bare rust function"); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1aade3663e6e..e83ac8a5e0c9c 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; +use trans::attributes; use trans::base::*; use trans::build::*; use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; @@ -164,7 +165,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); // set an inline hint for all closures - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?} (type {})", diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e154bc1d579ff..ce80c72b84785 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -13,6 +13,7 @@ use back::link; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; +use trans::attributes; use trans::base::{llvm_linkage_by_name, push_ctxt}; use trans::base; use trans::build::*; @@ -612,7 +613,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id, t.repr(tcx)); let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); - base::set_llvm_fn_attrs(ccx, attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn } diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c7857d6a775f3..0face6860dce5 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -19,43 +19,44 @@ pub use self::common::gensym_name; #[macro_use] mod macros; -mod inline; -mod monomorphize; -mod controlflow; -mod glue; -mod datum; -mod callee; -mod expr; -mod common; -mod context; -mod consts; -mod type_of; +mod adt; +mod asm; +mod attributes; +mod base; +mod basic_block; mod build; mod builder; -mod base; -mod _match; -mod closure; -mod tvec; -mod meth; mod cabi; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_arm; mod cabi_aarch64; +mod cabi_arm; mod cabi_mips; mod cabi_powerpc; +mod cabi_x86; +mod cabi_x86_64; +mod cabi_x86_win64; +mod callee; +mod cleanup; +mod closure; +mod common; +mod consts; +mod context; +mod controlflow; +mod datum; +mod debuginfo; +mod expr; mod foreign; +mod glue; +mod inline; mod intrinsic; -mod debuginfo; +mod llrepr; mod machine; -mod adt; -mod asm; +mod _match; +mod meth; +mod monomorphize; +mod tvec; mod type_; +mod type_of; mod value; -mod basic_block; -mod llrepr; -mod cleanup; #[derive(Copy, Clone)] pub struct ModuleTranslation { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index dcb21c5cd93b1..fc08b1a107944 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,7 +17,7 @@ use middle::subst; use middle::subst::{Subst, Substs}; use middle::traits; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use trans::base::{set_llvm_fn_attrs, set_inline_hint}; +use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::{trans_fn, decl_internal_rust_fn}; use trans::base; @@ -151,7 +151,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - set_llvm_fn_attrs(ccx, attrs, lldecl); + attributes::convert_fn_attrs_to_llvm(ccx, attrs, lldecl); let is_first = !ccx.available_monomorphizations().borrow().contains(&s); if is_first { @@ -200,7 +200,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineHint); match v.node.kind { ast::TupleVariantKind(ref args) => { trans_enum_variant(ccx, @@ -259,7 +259,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineHint); base::trans_tuple_struct(ccx, &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \ From cb4570311bda1789761a98997bbe57ac6c794101 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 28 Feb 2015 23:55:50 +0200 Subject: [PATCH 07/14] Move get_extern_fn and get_res_dtor out of base These functions have only a single use and functionally belong to foreign and glue respectively anyway --- src/librustc_trans/trans/base.rs | 61 +---------------------------- src/librustc_trans/trans/foreign.rs | 24 +++++++++--- src/librustc_trans/trans/glue.rs | 52 ++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 25750b6ec0e14..5dfa84c15d040 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -54,7 +54,7 @@ use trans::cleanup; use trans::closure; use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral}; use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use trans::common::{CrateContext, ExternMap, FunctionContext}; +use trans::common::{CrateContext, FunctionContext}; use trans::common::{Result, NodeIdAndSpan}; use trans::common::{node_id_type, return_type_is_void}; use trans::common::{type_is_immediate, type_is_zero_size, val_ty}; @@ -67,7 +67,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::expr; use trans::foreign; use trans::glue; -use trans::inline; use trans::intrinsic; use trans::machine; use trans::machine::{llsize_of, llsize_of_real}; @@ -84,7 +83,7 @@ use util::sha2::Sha256; use util::nodemap::NodeMap; use arena::TypedArena; -use libc::{c_uint, uint64_t}; +use libc::c_uint; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; @@ -218,23 +217,6 @@ pub fn decl_cdecl_fn(ccx: &CrateContext, decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output)) } -// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions -pub fn get_extern_fn(ccx: &CrateContext, - externs: &mut ExternMap, - name: &str, - cc: llvm::CallConv, - ty: Type, - output: Ty) - -> ValueRef { - match externs.get(name) { - Some(n) => return *n, - None => {} - } - let f = decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); - externs.insert(name.to_string(), f); - f -} - fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str, did: ast::DefId) -> ValueRef { match ccx.externs().borrow().get(name) { @@ -400,45 +382,6 @@ pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: String) { ccx.all_llvm_symbols().borrow_mut().insert(sym); } - -pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - did: ast::DefId, - t: Ty<'tcx>, - parent_id: ast::DefId, - substs: &Substs<'tcx>) - -> ValueRef { - let _icx = push_ctxt("trans_res_dtor"); - let did = inline::maybe_instantiate_inline(ccx, did); - - if !substs.types.is_empty() { - assert_eq!(did.krate, ast::LOCAL_CRATE); - - // Since we're in trans we don't care for any region parameters - let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); - - let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); - - val - } else if did.krate == ast::LOCAL_CRATE { - get_item_val(ccx, did.node) - } else { - let tcx = ccx.tcx(); - let name = csearch::get_symbol(&ccx.sess().cstore, did); - let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); - let llty = type_of_dtor(ccx, class_ty); - let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), - did, - &[glue::get_drop_glue_type(ccx, t)], - ty::mk_nil(ccx.tcx())); - get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - &name[..], - llvm::CCallConv, - llty, - dtor_ty) - } -} - pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool) -> llvm::IntPredicate { match op { diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index ce80c72b84785..e0299ba63f526 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -165,6 +165,23 @@ pub fn register_static(ccx: &CrateContext, } } +// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions +pub fn get_extern_fn(ccx: &CrateContext, + externs: &mut ExternMap, + name: &str, + cc: llvm::CallConv, + ty: Type, + output: Ty) + -> ValueRef { + match externs.get(name) { + Some(n) => return *n, + None => {} + } + let f = base::decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); + externs.insert(name.to_string(), f); + f +} + /// Registers a foreign function found in a library. Just adds a LLVM global. pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, abi: Abi, fty: Ty<'tcx>, @@ -190,12 +207,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Create the LLVM value for the C extern fn let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); - let llfn = base::get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - name, - cc, - llfn_ty, - fty); + let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); add_argument_attributes(&tys, llfn); llfn diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 32b4d14177c2a..898d4216e5a6b 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -15,11 +15,13 @@ use back::abi; use back::link::*; -use llvm::{ValueRef, get_param}; use llvm; +use llvm::{ValueRef, get_param}; +use metadata::csearch; use middle::lang_items::ExchangeFreeFnLangItem; use middle::subst; use middle::subst::{Subst, Substs}; +use middle::ty::{self, Ty}; use trans::adt; use trans::adt::GetDtorType; // for tcx.dtor_type() use trans::base::*; @@ -28,15 +30,19 @@ use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; +use trans::consts; use trans::datum; use trans::debuginfo::DebugLoc; use trans::expr; +use trans::foreign; +use trans::inline; use trans::machine::*; -use trans::type_::Type; +use trans::monomorphize; +use trans::tvec; use trans::type_of::{type_of, sizing_type_of, align_of}; -use middle::ty::{self, Ty}; -use util::ppaux::{ty_to_short_str, Repr}; +use trans::type_::Type; use util::ppaux; +use util::ppaux::{ty_to_short_str, Repr}; use arena::TypedArena; use libc::c_uint; @@ -259,6 +265,44 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } +pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + did: ast::DefId, + t: Ty<'tcx>, + parent_id: ast::DefId, + substs: &Substs<'tcx>) + -> ValueRef { + let _icx = push_ctxt("trans_res_dtor"); + let did = inline::maybe_instantiate_inline(ccx, did); + + if !substs.types.is_empty() { + assert_eq!(did.krate, ast::LOCAL_CRATE); + + // Since we're in trans we don't care for any region parameters + let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); + + let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); + + val + } else if did.krate == ast::LOCAL_CRATE { + get_item_val(ccx, did.node) + } else { + let tcx = ccx.tcx(); + let name = csearch::get_symbol(&ccx.sess().cstore, did); + let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); + let llty = type_of_dtor(ccx, class_ty); + let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), + did, + &[get_drop_glue_type(ccx, t)], + ty::mk_nil(ccx.tcx())); + foreign::get_extern_fn(ccx, + &mut *ccx.externs().borrow_mut(), + &name[..], + llvm::CCallConv, + llty, + dtor_ty) + } +} + fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, From deb097a1d252d3681d790db56cd44080bb34a6bd Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 00:57:44 +0200 Subject: [PATCH 08/14] Implement LLVMGetOrInsertGlobal wrapper --- src/librustc_llvm/lib.rs | 1 + src/rustllvm/RustWrapper.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 3eaa354c5e6da..7030ee5697954 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -912,6 +912,7 @@ extern { AddressSpace: c_uint) -> ValueRef; pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef; pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index ccdc3566c0935..31f75ae03b099 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -89,6 +89,12 @@ extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, unwrap(FunctionTy))); } +extern "C" LLVMValueRef LLVMGetOrInsertGlobal(LLVMModuleRef M, + const char* Name, + LLVMTypeRef Ty) { + return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); +} + extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } From caea044929decd3901aa64ef01126b32842f1a4e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 01:03:25 +0200 Subject: [PATCH 09/14] Move a big attribute fn into trans::attributes --- src/librustc_trans/trans/attributes.rs | 193 +++++++++++++++++++++-- src/librustc_trans/trans/base.rs | 186 +--------------------- src/librustc_trans/trans/closure.rs | 2 +- src/librustc_trans/trans/foreign.rs | 7 +- src/librustc_trans/trans/monomorphize.rs | 6 +- 5 files changed, 199 insertions(+), 195 deletions(-) diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 76034420e4b97..a8e9ef98d71d9 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -9,13 +9,17 @@ // except according to those terms. //! Set and unset common attributes on LLVM values. +use libc::{c_uint, c_ulonglong}; use llvm::{self, ValueRef, AttrHelper}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; use syntax::ast; -use syntax::attr::InlineAttr; -pub use syntax::attr::InlineAttr::*; +pub use syntax::attr::InlineAttr; +use trans::base; +use trans::common; use trans::context::CrateContext; - -use libc::{c_uint, c_ulonglong}; +use trans::machine; +use trans::type_of; /// Mark LLVM function to use split stack. #[inline] @@ -33,11 +37,12 @@ pub fn split_stack(val: ValueRef, set: bool) { /// Mark LLVM function to use provided inline heuristic. #[inline] pub fn inline(val: ValueRef, inline: InlineAttr) { + use self::InlineAttr::*; match inline { - InlineHint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), - InlineAlways => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), - InlineNever => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), - InlineNone => { + Hint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), + Always => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), + Never => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), + None => { let attr = llvm::InlineHintAttribute | llvm::AlwaysInlineAttribute | llvm::NoInlineAttribute; @@ -88,7 +93,7 @@ pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. -pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { +pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { use syntax::attr::*; inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); @@ -106,3 +111,173 @@ pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], ll } } } + +/// Composite function which converts function type into LLVM attributes for the function. +pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx>) + -> llvm::AttrBuilder { + use middle::ty::{BrAnon, ReLateBound}; + + let function_type; + let (fn_sig, abi, env_ty) = match fn_type.sty { + ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), + ty::ty_closure(closure_did, substs) => { + let typer = common::NormalizingClosureTyper::new(ccx.tcx()); + function_type = typer.closure_type(closure_did, substs); + let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); + (&function_type.sig, abi::RustCall, Some(self_type)) + } + _ => ccx.sess().bug("expected closure or function.") + }; + + let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + + let mut attrs = llvm::AttrBuilder::new(); + let ret_ty = fn_sig.output; + + // These have an odd calling convention, so we need to manually + // unpack the input ty's + let input_tys = match fn_type.sty { + ty::ty_closure(..) => { + assert!(abi == abi::RustCall); + + match fn_sig.inputs[0].sty { + ty::ty_tup(ref inputs) => { + let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; + full_inputs.push_all(inputs); + full_inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + }, + ty::ty_bare_fn(..) if abi == abi::RustCall => { + let mut inputs = vec![fn_sig.inputs[0]]; + + match fn_sig.inputs[1].sty { + ty::ty_tup(ref t_in) => { + inputs.push_all(&t_in[..]); + inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + } + _ => fn_sig.inputs.clone() + }; + + // Index 0 is the return value of the llvm func, so we start at 1 + let mut first_arg_offset = 1; + if let ty::FnConverging(ret_ty) = ret_ty { + // A function pointer is called without the declaration + // available, so we have to apply any attributes with ABI + // implications directly to the call instruction. Right now, + // the only attribute we need to worry about is `sret`. + if type_of::return_uses_outptr(ccx, ret_ty) { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); + + // The outptr can be noalias and nocapture because it's entirely + // invisible to the program. We also know it's nonnull as well + // as how many bytes we can dereference + attrs.arg(1, llvm::StructRetAttribute) + .arg(1, llvm::NoAliasAttribute) + .arg(1, llvm::NoCaptureAttribute) + .arg(1, llvm::DereferenceableAttribute(llret_sz)); + + // Add one more since there's an outptr + first_arg_offset += 1; + } else { + // The `noalias` attribute on the return value is useful to a + // function ptr caller. + match ret_ty.sty { + // `~` pointer return values never alias because ownership + // is transferred + ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {} + ty::ty_uniq(_) => { + attrs.ret(llvm::NoAliasAttribute); + } + _ => {} + } + + // We can also mark the return value as `dereferenceable` in certain cases + match ret_ty.sty { + // These are not really pointers but pairs, (pointer, len) + ty::ty_uniq(it) | + ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {} + ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + attrs.ret(llvm::DereferenceableAttribute(llret_sz)); + } + _ => {} + } + + if let ty::ty_bool = ret_ty.sty { + attrs.ret(llvm::ZExtAttribute); + } + } + } + + for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { + match t.sty { + // this needs to be first to prevent fat pointers from falling through + _ if !common::type_is_immediate(ccx, t) => { + let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t)); + + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); + } + + ty::ty_bool => { + attrs.arg(idx, llvm::ZExtAttribute); + } + + // `~` pointer parameters never alias because ownership is transferred + ty::ty_uniq(inner) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // `&mut` pointer parameters never alias other parameters, or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both + // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on + // memory dependencies rather than pointer equality + ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || + !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { + + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + + if mt.mutbl == ast::MutImmutable { + attrs.arg(idx, llvm::ReadOnlyAttribute); + } + + if let ReLateBound(_, BrAnon(_)) = *b { + attrs.arg(idx, llvm::NoCaptureAttribute); + } + } + + // When a reference in an argument has no named lifetime, it's impossible for that + // reference to escape this function (returned or stored beyond the call by a closure). + ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // & pointer parameters are also never null and we know exactly how + // many bytes we can dereference + ty::ty_rptr(_, mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + } + _ => () + } + } + + attrs +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 5dfa84c15d040..a1fa4e77a131b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -227,7 +227,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, let f = decl_rust_fn(ccx, fn_ty, name); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - attributes::convert_fn_attrs_to_llvm(ccx, &attrs[..], f); + attributes::from_fn_attrs(ccx, &attrs[..], f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -770,7 +770,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => { let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); llfn } } @@ -792,7 +792,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return (C_null(Type::i8(bcx.ccx())), bcx); } - let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + let attributes = attributes::from_fn_type(bcx.ccx(), fn_ty); match bcx.opt_node_id { None => { @@ -2226,176 +2226,6 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } -pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>) - -> llvm::AttrBuilder -{ - use middle::ty::{BrAnon, ReLateBound}; - - let function_type; - let (fn_sig, abi, env_ty) = match fn_ty.sty { - ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), - ty::ty_closure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); - let self_type = self_type_for_closure(ccx, closure_did, fn_ty); - (&function_type.sig, RustCall, Some(self_type)) - } - _ => ccx.sess().bug("expected closure or function.") - }; - - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); - - let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; - - // These have an odd calling convention, so we need to manually - // unpack the input ty's - let input_tys = match fn_ty.sty { - ty::ty_closure(..) => { - assert!(abi == RustCall); - - match fn_sig.inputs[0].sty { - ty::ty_tup(ref inputs) => { - let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; - full_inputs.push_all(inputs); - full_inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - }, - ty::ty_bare_fn(..) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; - - match fn_sig.inputs[1].sty { - ty::ty_tup(ref t_in) => { - inputs.push_all(&t_in[..]); - inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - } - _ => fn_sig.inputs.clone() - }; - - // Index 0 is the return value of the llvm func, so we start at 1 - let mut first_arg_offset = 1; - if let ty::FnConverging(ret_ty) = ret_ty { - // A function pointer is called without the declaration - // available, so we have to apply any attributes with ABI - // implications directly to the call instruction. Right now, - // the only attribute we need to worry about is `sret`. - if type_of::return_uses_outptr(ccx, ret_ty) { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); - - // The outptr can be noalias and nocapture because it's entirely - // invisible to the program. We also know it's nonnull as well - // as how many bytes we can dereference - attrs.arg(1, llvm::StructRetAttribute) - .arg(1, llvm::NoAliasAttribute) - .arg(1, llvm::NoCaptureAttribute) - .arg(1, llvm::DereferenceableAttribute(llret_sz)); - - // Add one more since there's an outptr - first_arg_offset += 1; - } else { - // The `noalias` attribute on the return value is useful to a - // function ptr caller. - match ret_ty.sty { - // `~` pointer return values never alias because ownership - // is transferred - ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(_) => { - attrs.ret(llvm::NoAliasAttribute); - } - _ => {} - } - - // We can also mark the return value as `dereferenceable` in certain cases - match ret_ty.sty { - // These are not really pointers but pairs, (pointer, len) - ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - attrs.ret(llvm::DereferenceableAttribute(llret_sz)); - } - _ => {} - } - - if let ty::ty_bool = ret_ty.sty { - attrs.ret(llvm::ZExtAttribute); - } - } - } - - for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { - match t.sty { - // this needs to be first to prevent fat pointers from falling through - _ if !type_is_immediate(ccx, t) => { - let llarg_sz = llsize_of_real(ccx, type_of::type_of(ccx, t)); - - // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases. It's also - // program-invisible so can't possibly capture - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); - } - - ty::ty_bool => { - attrs.arg(idx, llvm::ZExtAttribute); - } - - // `~` pointer parameters never alias because ownership is transferred - ty::ty_uniq(inner) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // `&mut` pointer parameters never alias other parameters, or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both - // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on - // memory dependencies rather than pointer equality - ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || - !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { - - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - - if mt.mutbl == ast::MutImmutable { - attrs.arg(idx, llvm::ReadOnlyAttribute); - } - - if let ReLateBound(_, BrAnon(_)) = *b { - attrs.arg(idx, llvm::NoCaptureAttribute); - } - } - - // When a reference in an argument has no named lifetime, it's impossible for that - // reference to escape this function (returned or stored beyond the call by a closure). - ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // & pointer parameters are also never null and we know exactly how - // many bytes we can dereference - ty::ty_rptr(_, mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); - } - _ => () - } - } - - attrs -} - // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions pub fn register_fn_llvmty(ccx: &CrateContext, sp: Span, @@ -2605,7 +2435,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sym, i.id) }; - attributes::convert_fn_attrs_to_llvm(ccx, &i.attrs, llfn); + attributes::from_fn_attrs(ccx, &i.attrs, llfn); llfn } @@ -2666,7 +2496,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - attributes::convert_fn_attrs_to_llvm(ccx, &ni.attrs, llfn); + attributes::from_fn_attrs(ccx, &ni.attrs, llfn); llfn } ast::ForeignItemStatic(..) => { @@ -2698,7 +2528,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; - attributes::inline(llfn, attributes::InlineHint); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2720,7 +2550,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); - attributes::inline(llfn, attributes::InlineHint); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2755,7 +2585,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, } else { foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) }; - attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); return llfn; } else { ccx.sess().span_bug(span, "expected bare rust function"); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index e83ac8a5e0c9c..c343d705e866f 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -165,7 +165,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); // set an inline hint for all closures - attributes::inline(llfn, attributes::InlineHint); + attributes::inline(llfn, attributes::InlineAttr::Hint); debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?} (type {})", diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e0299ba63f526..20da3c1c9f895 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -209,7 +209,6 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); add_argument_attributes(&tys, llfn); - llfn } @@ -484,7 +483,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { } let llfn = register_foreign_item_fn(ccx, abi, ty, &lname); - base::set_llvm_fn_attrs(ccx, &foreign_item.attrs, llfn); + attributes::from_fn_attrs(ccx, &foreign_item.attrs, llfn); // Unlike for other items, we shouldn't call // `base::update_linkage` here. Foreign items have // special linkage requirements, which are handled @@ -625,7 +624,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id, t.repr(tcx)); let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); - attributes::convert_fn_attrs_to_llvm(ccx, attrs, llfn); + attributes::from_fn_attrs(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn } @@ -818,7 +817,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Perform the call itself debug!("calling llrustfn = {}, t = {}", ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx())); - let attributes = base::get_fn_llvm_attributes(ccx, t); + let attributes = attributes::from_fn_type(ccx, t); let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes)); // Get the return value where the foreign fn expects it. diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index fc08b1a107944..862eb31303e4f 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -151,7 +151,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - attributes::convert_fn_attrs_to_llvm(ccx, attrs, lldecl); + attributes::from_fn_attrs(ccx, attrs, lldecl); let is_first = !ccx.available_monomorphizations().borrow().contains(&s); if is_first { @@ -200,7 +200,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); - attributes::inline(d, attributes::InlineHint); + attributes::inline(d, attributes::InlineAttr::Hint); match v.node.kind { ast::TupleVariantKind(ref args) => { trans_enum_variant(ccx, @@ -259,7 +259,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); - attributes::inline(d, attributes::InlineHint); + attributes::inline(d, attributes::InlineAttr::Hint); base::trans_tuple_struct(ccx, &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \ From f1dabed82bfed643fbbfc93203473e384c58d20a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 01:08:06 +0200 Subject: [PATCH 10/14] Introduce trans::declare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We provide tools to tell what exact symbols to emit for any fn or static, but don’t quite check if that won’t cause any issues later on. Some of the issues include LLVM mangling our names again and our names pointing to wrong locations, us generating dumb foreign call wrappers, linker errors, extern functions resolving to different symbols altogether (extern {fn fail();} fail(); in some cases calling fail1()), etc. Before the commit we had a function called note_unique_llvm_symbol, so it is clear somebody was aware of the issue at some point, but the function was barely used, mostly in irrelevant locations. Along with working on it I took liberty to start refactoring trans/base into a few smaller modules. The refactoring is incomplete and I hope I will find some motivation to carry on with it. This is possibly a [breaking-change] because it makes dumbly written code properly invalid. --- src/librustc_trans/trans/base.rs | 280 +++++++---------------- src/librustc_trans/trans/callee.rs | 11 +- src/librustc_trans/trans/cleanup.rs | 7 +- src/librustc_trans/trans/closure.rs | 7 +- src/librustc_trans/trans/common.rs | 8 +- src/librustc_trans/trans/consts.rs | 33 +-- src/librustc_trans/trans/context.rs | 22 +- src/librustc_trans/trans/controlflow.rs | 6 +- src/librustc_trans/trans/debuginfo.rs | 16 +- src/librustc_trans/trans/declare.rs | 263 +++++++++++++++++++++ src/librustc_trans/trans/foreign.rs | 29 ++- src/librustc_trans/trans/glue.rs | 11 +- src/librustc_trans/trans/meth.rs | 12 +- src/librustc_trans/trans/mod.rs | 1 + src/librustc_trans/trans/monomorphize.rs | 8 +- 15 files changed, 430 insertions(+), 284 deletions(-) create mode 100644 src/librustc_trans/trans/declare.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index a1fa4e77a131b..c7200fc8bb256 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -64,6 +64,7 @@ use trans::context::SharedCrateContext; use trans::controlflow; use trans::datum; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::foreign; use trans::glue; @@ -179,44 +180,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions -pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, - ty: Type, output: ty::FnOutput) -> ValueRef { - - let buf = CString::new(name).unwrap(); - let llfn: ValueRef = unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) - }; - - // diverging functions may unwind, but can never return normally - if output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); - } - - if ccx.tcx().sess.opts.cg.no_redzone - .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { - llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) - } - - llvm::SetFunctionCallConv(llfn, cc); - // Function addresses in Rust are never significant, allowing functions to be merged. - llvm::SetUnnamedAddr(llfn, true); - - if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { - attributes::split_stack(llfn, true); - } - - llfn -} - -// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions -pub fn decl_cdecl_fn(ccx: &CrateContext, - name: &str, - ty: Type, - output: Ty) -> ValueRef { - decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output)) -} - fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str, did: ast::DefId) -> ValueRef { match ccx.externs().borrow().get(name) { @@ -224,7 +187,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, None => () } - let f = decl_rust_fn(ccx, fn_ty, name); + let f = declare::declare_rust_fn(ccx, name, fn_ty); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); attributes::from_fn_attrs(ccx, &attrs[..], f); @@ -254,63 +217,6 @@ pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::Closu *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap() } -pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_ty: Ty<'tcx>, name: &str) -> ValueRef { - debug!("decl_rust_fn(fn_ty={}, name={:?})", - fn_ty.repr(ccx.tcx()), - name); - - let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty); - - debug!("decl_rust_fn: fn_ty={} (after normalized associated types)", - fn_ty.repr(ccx.tcx())); - - let function_type; // placeholder so that the memory ownership works out ok - - let (sig, abi, env) = match fn_ty.sty { - ty::ty_bare_fn(_, ref f) => { - (&f.sig, f.abi, None) - } - ty::ty_closure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); - let self_type = self_type_for_closure(ccx, closure_did, fn_ty); - let llenvironment_type = type_of_explicit_arg(ccx, self_type); - debug!("decl_rust_fn: function_type={} self_type={}", - function_type.repr(ccx.tcx()), - self_type.repr(ccx.tcx())); - (&function_type.sig, RustCall, Some(llenvironment_type)) - } - _ => ccx.sess().bug("expected closure or fn") - }; - - let sig = ty::erase_late_bound_regions(ccx.tcx(), sig); - let sig = ty::Binder(sig); - - debug!("decl_rust_fn: sig={} (after erasing regions)", - sig.repr(ccx.tcx())); - - let llfty = type_of_rust_fn(ccx, env, &sig, abi); - - debug!("decl_rust_fn: llfty={}", - ccx.tn().type_to_string(llfty)); - - let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */); - let attrs = get_fn_llvm_attributes(ccx, fn_ty); - attrs.apply_llfn(llfn); - - // (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above - - llfn -} - -pub fn decl_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_ty: Ty<'tcx>, name: &str) -> ValueRef { - let llfn = decl_rust_fn(ccx, fn_ty, name); - llvm::SetLinkage(llfn, llvm::InternalLinkage); - llfn -} - pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, t: Ty<'tcx>) -> ValueRef { let name = csearch::get_symbol(&ccx.sess().cstore, did); @@ -319,23 +225,22 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, Some(n) => return *n, None => () } - unsafe { - let buf = CString::new(name.clone()).unwrap(); - let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); - // 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 - // thread-local attribute locally if it was present remotely. If we - // 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. - for attr in &*ty::get_attrs(ccx.tcx(), did) { - if attr.check_name("thread_local") { - llvm::set_thread_local(c, true); - } + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + // FIXME(nagisa): investigate whether it can be changed into define_global + let c = declare::declare_global(ccx, &name[..], ty); + // 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 + // thread-local attribute locally if it was present remotely. If we + // 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. + for attr in &*ty::get_attrs(ccx.tcx(), did) { + if attr.check_name("thread_local") { + llvm::set_thread_local(c, true); } - ccx.externs().borrow_mut().insert(name.to_string(), c); - return c; } + ccx.externs().borrow_mut().insert(name.to_string(), c); + return c; } fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -373,15 +278,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } -// Double-check that we never ask LLVM to declare the same symbol twice. It -// silently mangles such symbols, breaking our linkage model. -pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: String) { - if ccx.all_llvm_symbols().borrow().contains(&sym) { - ccx.sess().bug(&format!("duplicate LLVM symbol: {}", sym)); - } - ccx.all_llvm_symbols().borrow_mut().insert(sym); -} - pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool) -> llvm::IntPredicate { match op { @@ -1713,15 +1609,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let fn_ty = ty::node_id_to_type(ccx.tcx(), id); let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty)); let abi = ty::ty_fn_abi(fn_ty); - trans_closure(ccx, - decl, - body, - llfndecl, - param_substs, - id, - attrs, - output_type, - abi, + trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi, closure::ClosureEnv::NotClosure); } @@ -2066,27 +1954,24 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let llfn = get_item_val(ccx, item.id); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); if abi != Rust { - foreign::trans_rust_fn_with_foreign_abi(ccx, - &**decl, - &**body, - &item.attrs, - llfn, - empty_substs, - item.id, - None); + foreign::trans_rust_fn_with_foreign_abi(ccx, &**decl, &**body, &item.attrs, + llfn, empty_substs, item.id, None); } else { - trans_fn(ccx, - &**decl, - &**body, - llfn, - empty_substs, - item.id, - &item.attrs); + trans_fn(ccx, &**decl, &**body, llfn, empty_substs, item.id, &item.attrs); } - update_linkage(ccx, - llfn, - Some(item.id), + update_linkage(ccx, llfn, Some(item.id), if is_origin { OriginalTranslation } else { InlinedCopy }); + + if is_entry_fn(ccx.sess(), item.id) { + create_entry_wrapper(ccx, item.span, llfn); + // check for the #[rustc_error] annotation, which forces an + // error in trans. This is used to write compile-fail tests + // that actually test that compilation succeeds without + // reporting an error. + if ty::has_attr(ccx.tcx(), local_def(item.id), "rustc_error") { + ccx.tcx().sess.span_fatal(item.span, "compilation successful"); + } + } } } @@ -2122,8 +2007,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let mut v = TransItemVisitor{ ccx: ccx }; v.visit_expr(&**expr); - consts::trans_static(ccx, m, item.id); - let g = get_item_val(ccx, item.id); + let g = consts::trans_static(ccx, m, item.id); update_linkage(ccx, g, Some(item.id), OriginalTranslation); // Do static_assert checking. It can't really be done much earlier @@ -2175,7 +2059,25 @@ pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) { } } -fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::NodeId, + +// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions +pub fn register_fn_llvmty(ccx: &CrateContext, + sp: Span, + sym: String, + node_id: ast::NodeId, + cc: llvm::CallConv, + llfty: Type) -> ValueRef { + debug!("register_fn_llvmty id={} sym={}", node_id, sym); + + let llfn = declare::define_fn(ccx, &sym[..], cc, llfty, + ty::FnConverging(ty::mk_nil(ccx.tcx()))).unwrap_or_else(||{ + ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); + }); + finish_register_fn(ccx, sym, node_id, llfn); + llfn +} + +fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId, llfn: ValueRef) { ccx.item_symbols().borrow_mut().insert(node_id, sym); @@ -2190,19 +2092,6 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N if ccx.tcx().lang_items.eh_personality() == Some(def) { llvm::SetLinkage(llfn, llvm::ExternalLinkage); } - - - if is_entry_fn(ccx.sess(), node_id) { - // check for the #[rustc_error] annotation, which forces an - // error in trans. This is used to write compile-fail tests - // that actually test that compilation succeeds without - // reporting an error. - if ty::has_attr(ccx.tcx(), local_def(node_id), "rustc_error") { - ccx.tcx().sess.span_fatal(sp, "compilation successful"); - } - - create_entry_wrapper(ccx, sp, llfn); - } } fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -2221,26 +2110,10 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().span_bug(sp, "expected bare rust function") } - let llfn = decl_rust_fn(ccx, node_type, &sym[..]); - finish_register_fn(ccx, sp, sym, node_id, llfn); - llfn -} - -// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions -pub fn register_fn_llvmty(ccx: &CrateContext, - sp: Span, - sym: String, - node_id: ast::NodeId, - cc: llvm::CallConv, - llfty: Type) -> ValueRef { - debug!("register_fn_llvmty id={} sym={}", node_id, sym); - - let llfn = decl_fn(ccx, - &sym[..], - cc, - llfty, - ty::FnConverging(ty::mk_nil(ccx.tcx()))); - finish_register_fn(ccx, sp, sym, node_id, llfn); + let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(||{ + ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); + }); + finish_register_fn(ccx, sym, node_id, llfn); llfn } @@ -2251,27 +2124,36 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool { } } -// Create a _rust_main(args: ~[str]) function which will be called from the -// runtime rust_start function +/// Create the `main` function which will initialise the rust runtime and call users’ main +/// function. pub fn create_entry_wrapper(ccx: &CrateContext, _sp: Span, main_llfn: ValueRef) { let et = ccx.sess().entry_type.get().unwrap(); match et { config::EntryMain => { - create_entry_fn(ccx, main_llfn, true); + create_entry_fn(ccx, _sp, main_llfn, true); } - config::EntryStart => create_entry_fn(ccx, main_llfn, false), + config::EntryStart => create_entry_fn(ccx, _sp, main_llfn, false), config::EntryNone => {} // Do nothing. } + #[inline(never)] fn create_entry_fn(ccx: &CrateContext, + _sp: Span, rust_main: ValueRef, use_start_lang_item: bool) { let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type()); - let llfn = decl_cdecl_fn(ccx, "main", llfty, ty::mk_nil(ccx.tcx())); + let llfn = declare::define_cfn(ccx, "main", llfty, + ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.sess().span_err(_sp, "entry symbol `main` defined multiple times"); + // FIXME: We should be smart and show a better diagnostic here. + ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead"); + ccx.sess().abort_if_errors(); + panic!(); + }); // FIXME: #16581: Marking a symbol in the executable with `dllexport` // linkage forces MinGW's linker to output a `.reloc` section for ASLR @@ -2407,14 +2289,15 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } else { llvm::LLVMTypeOf(v) }; - if contains_null(&sym[..]) { - ccx.sess().fatal( - &format!("Illegal null byte in export_name \ - value: `{}`", sym)); - } - let buf = CString::new(sym.clone()).unwrap(); - let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, - buf.as_ptr()); + + // FIXME(nagisa): probably should be declare_global, because no definition + // is happening here, but we depend on it being defined here from + // const::trans_static. This all logic should be replaced. + let g = declare::define_global(ccx, &sym[..], + Type::from_ref(llty)).unwrap_or_else(||{ + ccx.sess().span_fatal(i.span, &format!("symbol `{}` is already defined", + sym)) + }); if attr::contains_name(&i.attrs, "thread_local") { @@ -2430,10 +2313,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let llfn = if abi == Rust { register_fn(ccx, i.span, sym, i.id, ty) } else { - foreign::register_rust_fn_with_foreign_abi(ccx, - i.span, - sym, - i.id) + foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id) }; attributes::from_fn_attrs(ccx, &i.attrs, llfn); llfn diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 9eb46d3ff549a..604f185f396b8 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -41,6 +41,7 @@ use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, use trans::consts; use trans::datum::*; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::glue; use trans::inline; @@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); - let llfn = - decl_internal_rust_fn(ccx, - tuple_fn_ty, - &function_name[..]); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, + "fn_pointer_shim"); + let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty); // let empty_substs = tcx.mk_substs(Substs::trans_empty()); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 19891e9307229..61af5bfaef8de 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -126,6 +126,7 @@ use trans::callee; use trans::common; use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::glue; use middle::region; use trans::type_::Type; @@ -844,10 +845,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx Some(llpersonality) => llpersonality, None => { let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = base::decl_cdecl_fn(self.ccx, - "rust_eh_personality", - fty, - self.ccx.tcx().types.i32); + let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty, + self.ccx.tcx().types.i32); *personality = Some(f); f } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c343d705e866f..60d54cdebeb83 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -21,6 +21,7 @@ use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::expr; use trans::monomorphize::{self, MonoId}; use trans::type_of::*; @@ -162,7 +163,11 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc mangle_internal_name_by_path_and_seq(path, "closure") }); - let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); + // Currently there’s only a single user of get_or_create_declaration_if_closure and it + // unconditionally defines the function, therefore we use define_* here. + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); + }); // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index c5985e930e97b..153242353d49f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -31,6 +31,7 @@ use trans::cleanup; use trans::consts; use trans::datum; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -872,9 +873,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let buf = CString::new(format!("str{}", gsym.usize())); - let buf = buf.unwrap(); - let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); + let sym = format!("str{}", gsym.usize()); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + cx.sess().bug(&format!("symbol `{}` is already defined", sym)); + }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c32cb28ec78db..336e68f1e8b49 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -25,6 +25,7 @@ use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; +use trans::declare; use trans::monomorphize; use trans::type_::Type; use trans::type_of; @@ -35,6 +36,7 @@ use util::ppaux::{Repr, ty_to_string}; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; +use syntax::parse::token; use syntax::ptr::P; pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) @@ -96,13 +98,16 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { fn addr_of_mut(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { unsafe { - let name = format!("{}{}\0", kind, id); - let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(), - name.as_ptr() as *const _); + // FIXME: this totally needs a better name generation scheme, perhaps a simple global + // counter? Also most other uses of gensym in trans. + let gsym = token::gensym("_"); + let name = format!("{}{}", kind, gsym.usize()); + let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", name)); + }); llvm::LLVMSetInitializer(gv, cv); SetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); @@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { match ccx.const_globals().borrow().get(&cv) { Some(&gv) => return gv, None => {} } - let gv = addr_of_mut(ccx, cv, kind, id); + let gv = addr_of_mut(ccx, cv, kind); unsafe { llvm::LLVMSetGlobalConstant(gv, True); } @@ -233,7 +237,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } }; - let lvalue = addr_of(ccx, val, "const", expr.id); + let lvalue = addr_of(ccx, val, "const"); ccx.const_values().borrow_mut().insert(key, lvalue); lvalue } @@ -284,7 +288,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if adj.autoderefs == 0 { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref", e.id); + llconst = addr_of(cx, llconst, "autoref"); } else { // Seeing as we are deref'ing here and take a reference // again to make the pointer part of the far pointer below, @@ -312,7 +316,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, None => {} Some(box ty::AutoUnsafe(_, None)) | Some(box ty::AutoPtr(_, _, None)) => { - llconst = addr_of(cx, llconst, "autoref", e.id); + llconst = addr_of(cx, llconst, "autoref"); } Some(box ty::AutoUnsize(ref k)) => { let info = @@ -711,12 +715,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // If this isn't the address of a static, then keep going through // normal constant evaluation. let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of(cx, v, "ref", e.id) + addr_of(cx, v, "ref") } } ast::ExprAddrOf(ast::MutMutable, ref sub) => { let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of_mut(cx, v, "ref_mut_slice", e.id) + addr_of_mut(cx, v, "ref_mut_slice") } ast::ExprTup(ref es) => { let repr = adt::represent_type(cx, ety); @@ -862,7 +866,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } -pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { +pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> ValueRef { unsafe { let _icx = push_ctxt("trans_static"); let g = base::get_item_val(ccx, id); @@ -888,6 +892,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { } } debuginfo::create_global_var_metadata(ccx, id, g); + g } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 8919a386a45fb..e54962dc08552 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -20,6 +20,7 @@ use trans::base; use trans::builder::Builder; use trans::common::{ExternMap,BuilderRef_res}; use trans::debuginfo; +use trans::declare; use trans::monomorphize::MonoId; use trans::type_::{Type, TypeNames}; use middle::subst::Substs; @@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> { llsizingtypes: RefCell, Type>>, adt_reprs: RefCell, Rc>>>, type_hashcodes: RefCell, String>>, - all_llvm_symbols: RefCell>, int_type: Type, opaque_vec_type: Type, builder: BuilderRef_res, @@ -413,7 +413,6 @@ impl<'tcx> LocalCrateContext<'tcx> { llsizingtypes: RefCell::new(FnvHashMap()), adt_reprs: RefCell::new(FnvHashMap()), type_hashcodes: RefCell::new(FnvHashMap()), - all_llvm_symbols: RefCell::new(FnvHashSet()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), @@ -653,10 +652,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.type_hashcodes } - pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell> { - &self.local.all_llvm_symbols - } - pub fn stats<'a>(&'a self) -> &'a Stats { &self.shared.stats } @@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn( - ccx, $name, Type::func(&[], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn(ccx, $name, - Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret); } else if *key == $name { - let f = base::decl_cdecl_fn(ccx, stringify!($cname), - Type::func(&[$($arg),*], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, stringify!($cname), + Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 5b1ac88c2089b..3ce883af07f6a 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -417,8 +417,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); - let expr_file_line = consts::addr_of(ccx, expr_file_line_const, - "panic_loc", call_info.id); + let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc"); let args = vec!(expr_file_line); let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem); let bcx = callee::trans_lang_call(bcx, @@ -450,8 +449,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::addr_of(ccx, file_line_const, - "panic_bounds_check_loc", call_info.id); + let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 2747288b60755..a32b40dc2b640 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -196,8 +196,9 @@ use llvm::debuginfo::*; use metadata::csearch; use middle::subst::{self, Substs}; use trans::{self, adt, machine, type_of}; -use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, - C_bytes, NormalizingClosureTyper}; +use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes, + NormalizingClosureTyper}; +use trans::declare; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::monomorphize; use trans::type_::Type; @@ -4071,7 +4072,7 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) /// section. fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) -> llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; + let section_var_name = "__rustc_debug_gdb_scripts_section__"; let section_var = unsafe { llvm::LLVMGetNamedGlobal(ccx.llmod(), @@ -4085,10 +4086,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) unsafe { let llvm_type = Type::array(&Type::i8(ccx), section_contents.len() as u64); - let section_var = llvm::LLVMAddGlobal(ccx.llmod(), - llvm_type.to_ref(), - section_var_name.as_ptr() - as *const _); + + let section_var = declare::define_global(ccx, section_var_name, + llvm_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name)) + }); llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs new file mode 100644 index 0000000000000..147b5161a4ac2 --- /dev/null +++ b/src/librustc_trans/trans/declare.rs @@ -0,0 +1,263 @@ +// Copyright 2012-2015 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. +//! Declare various LLVM values. +//! +//! Prefer using functions and methods from this module rather than calling LLVM functions +//! directly. These functions do some additional work to ensure we do the right thing given +//! the preconceptions of trans. +//! +//! Some useful guidelines: +//! +//! * Use declare_* family of methods if you are declaring, but are not interested in defining the +//! ValueRef they return. +//! * Use define_* family of methods when you might be defining the ValueRef. +//! * When in doubt, define. +#![allow(dead_code)] + +use llvm::{self, ValueRef}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; +use trans::attributes; +use trans::base; +use trans::common; +use trans::context::CrateContext; +use trans::monomorphize; +use trans::type_::Type; +use trans::type_of; +use util::ppaux::Repr; + +use std::ffi::CString; +use libc::c_uint; + + +/// Declare a global value. +/// +/// If there’s a value with the same name already declared, the function will return its ValueRef +/// instead. +pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef { + debug!("declare_global(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + unsafe { + llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + } +} + + +/// Declare a function. +/// +/// For rust functions use `declare_rust_fn` instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type, + output: ty::FnOutput) -> ValueRef { + debug!("declare_fn(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let llfn = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + }; + + llvm::SetFunctionCallConv(llfn, callconv); + // Function addresses in Rust are never significant, allowing functions to be merged. + llvm::SetUnnamedAddr(llfn, true); + + if output == ty::FnDiverging { + llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); + } + + if ccx.tcx().sess.opts.cg.no_redzone + .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { + llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) + } + + if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { + attributes::split_stack(llfn, true); + } + llfn +} + + +/// Declare a C ABI function. +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef { + declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output)) +} + + +/// Declare a Rust function. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx())); + let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type); + debug!("declare_rust_fn (after normalised associated types) fn_type={}", + fn_type.repr(ccx.tcx())); + + let function_type; // placeholder so that the memory ownership works out ok + let (sig, abi, env) = match fn_type.sty { + ty::ty_bare_fn(_, ref f) => { + (&f.sig, f.abi, None) + } + ty::ty_closure(closure_did, substs) => { + let typer = common::NormalizingClosureTyper::new(ccx.tcx()); + function_type = typer.closure_type(closure_did, substs); + let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); + let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type); + debug!("declare_rust_fn function_type={} self_type={}", + function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx())); + (&function_type.sig, abi::RustCall, Some(llenvironment_type)) + } + _ => ccx.sess().bug("expected closure or fn") + }; + + let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig)); + debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx())); + let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi); + debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty)); + + // it is ok to directly access sig.0.output because we erased all late-bound-regions above + let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output); + attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); + llfn +} + + +/// Declare a Rust function with internal linkage. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + let llfn = declare_rust_fn(ccx, name, fn_type); + llvm::SetLinkage(llfn, llvm::InternalLinkage); + llfn +} + + +/// Declare a global with an intention to define it. +/// +/// Use this function when you intend to define a global. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_global(ccx, name, ty)) + } +} + + +/// Declare a function with an intention to define it. +/// +/// For rust functions use `define_rust_fn` instead. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type, + output: ty::FnOutput) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_fn(ccx, name, callconv, fn_type, output)) + } +} + + +/// Declare a C ABI function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type, + output: ty::Ty) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_cfn(ccx, name, fn_type, output)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_rust_fn(ccx, name, fn_type)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_internal_rust_fn(ccx, name, fn_type)) + } +} + + +/// Get defined or externally defined (AvailableExternally linkage) value by name. +fn get_defined_value(ccx: &CrateContext, name: &str) -> Option { + debug!("get_defined_value(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; + if val.is_null() { + debug!("get_defined_value: {:?} value is null", name); + None + } else { + let (declaration, aext_link) = unsafe { + let linkage = llvm::LLVMGetLinkage(val); + (llvm::LLVMIsDeclaration(val) != 0, + linkage == llvm::AvailableExternallyLinkage as c_uint) + }; + debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name, + declaration, aext_link); + if !declaration || aext_link { + Some(val) + } else { + None + } + } +} diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 20da3c1c9f895..8f3a51a500709 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -20,6 +20,7 @@ use trans::build::*; use trans::cabi; use trans::common::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -28,7 +29,6 @@ use trans::type_of; use middle::ty::{self, Ty}; use middle::subst::Substs; -use std::ffi::CString; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; @@ -136,9 +136,7 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let buf = CString::new(ident.as_bytes()).unwrap(); - let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), - buf.as_ptr()); + let g1 = declare::declare_global(ccx, &ident[..], llty2); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -149,19 +147,17 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&ident); - let real_name = CString::new(real_name).unwrap(); - let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), - real_name.as_ptr()); + let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{ + ccx.sess().span_fatal(foreign_item.span, + &format!("symbol `{}` is already defined", ident)) + }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 } } - None => unsafe { - // Generate an external declaration. - let buf = CString::new(ident.as_bytes()).unwrap(); - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) - } + None => // Generate an external declaration. + declare::declare_global(ccx, &ident[..], llty), } } @@ -177,7 +173,7 @@ pub fn get_extern_fn(ccx: &CrateContext, Some(n) => return *n, None => {} } - let f = base::decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); + let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output)); externs.insert(name.to_string(), f); f } @@ -534,7 +530,8 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") }; - let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil(ccx.tcx()))); + let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty, + ty::FnConverging(ty::mk_nil(ccx.tcx()))); add_argument_attributes(&tys, llfn); debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})", ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn)); @@ -623,7 +620,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx().map.path_to_string(id), id, t.repr(tcx)); - let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); + let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", ps)); + }); attributes::from_fn_attrs(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 898d4216e5a6b..abcd2882b173e 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -33,6 +33,7 @@ use trans::common::*; use trans::consts; use trans::datum; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; use trans::foreign; use trans::inline; @@ -184,7 +185,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val // To avoid infinite recursion, don't `make_drop_glue` until after we've // added the entry to the `drop_glues` cache. if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) { - let llfn = decl_cdecl_fn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); + let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); ccx.drop_glues().borrow_mut().insert(t, llfn); return llfn; }; @@ -294,12 +295,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did, &[get_drop_glue_type(ccx, t)], ty::mk_nil(ccx.tcx())); - foreign::get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - &name[..], - llvm::CCallConv, - llty, - dtor_ty) + foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv, + llty, dtor_ty) } } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 190e44c9674cb..e2f965a95fff7 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -28,6 +28,7 @@ use trans::common::*; use trans::consts; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr::SaveIn; use trans::expr; use trans::glue; @@ -590,10 +591,10 @@ pub fn trans_object_shim<'a, 'tcx>( // let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty); let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = - decl_internal_rust_fn(ccx, shim_fn_ty, &function_name); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); + let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig); @@ -756,8 +757,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, C_uint(ccx, align) ].into_iter().chain(methods).collect(); - let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), - "vtable", trait_ref.def_id().node); + let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 0face6860dce5..7d568ff90ea43 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -43,6 +43,7 @@ mod context; mod controlflow; mod datum; mod debuginfo; +mod declare; mod expr; mod foreign; mod glue; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 862eb31303e4f..1c8d020494fab 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -19,9 +19,10 @@ use middle::traits; use middle::ty_fold::{TypeFolder, TypeFoldable}; use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; -use trans::base::{trans_fn, decl_internal_rust_fn}; +use trans::base::trans_fn; use trans::base; use trans::common::*; +use trans::declare; use trans::foreign; use middle::ty::{self, HasProjectionTypes, Ty}; use util::ppaux::Repr; @@ -143,7 +144,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) } else { - decl_internal_rust_fn(ccx, mono_ty, &s[..]) + // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below. + declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", s)); + }) }; ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); From 8943709221f745cdd58d9a19e9fd280ae53091c6 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 01:09:10 +0200 Subject: [PATCH 11/14] Update tests to match the messages --- src/test/compile-fail/dupe-symbols-1.rs | 2 +- src/test/compile-fail/dupe-symbols-2.rs | 2 +- src/test/compile-fail/dupe-symbols-3.rs | 2 +- src/test/compile-fail/dupe-symbols-4.rs | 2 +- src/test/compile-fail/dupe-symbols-5.rs | 2 +- src/test/compile-fail/dupe-symbols-6.rs | 2 +- src/test/compile-fail/dupe-symbols-7.rs | 12 +++--------- src/test/compile-fail/dupe-symbols-8.rs | 15 --------------- 8 files changed, 9 insertions(+), 30 deletions(-) delete mode 100644 src/test/compile-fail/dupe-symbols-8.rs diff --git a/src/test/compile-fail/dupe-symbols-1.rs b/src/test/compile-fail/dupe-symbols-1.rs index 08370b534cdf1..9fa4eafcad0ed 100644 --- a/src/test/compile-fail/dupe-symbols-1.rs +++ b/src/test/compile-fail/dupe-symbols-1.rs @@ -17,5 +17,5 @@ pub fn a() { #[export_name="fail"] pub fn b() { -//~^ symbol `fail` already exists +//~^ symbol `fail` is already defined } diff --git a/src/test/compile-fail/dupe-symbols-2.rs b/src/test/compile-fail/dupe-symbols-2.rs index 592874491e015..976a65589b869 100644 --- a/src/test/compile-fail/dupe-symbols-2.rs +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -20,6 +20,6 @@ mod a { mod b { #[no_mangle] pub extern fn fail() { - //~^ symbol `fail` already exists + //~^ symbol `fail` is already defined } } diff --git a/src/test/compile-fail/dupe-symbols-3.rs b/src/test/compile-fail/dupe-symbols-3.rs index af5622861ef71..98a61c33c584a 100644 --- a/src/test/compile-fail/dupe-symbols-3.rs +++ b/src/test/compile-fail/dupe-symbols-3.rs @@ -17,5 +17,5 @@ pub fn a() { #[no_mangle] pub fn fail() { -//~^ symbol `fail` already exists +//~^ symbol `fail` is already defined } diff --git a/src/test/compile-fail/dupe-symbols-4.rs b/src/test/compile-fail/dupe-symbols-4.rs index 738dce6fed1a3..60e68f72b2437 100644 --- a/src/test/compile-fail/dupe-symbols-4.rs +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -27,5 +27,5 @@ impl A for B { impl A for C { #[no_mangle] fn fail(self) {} - //~^ symbol `fail` already exists + //~^ symbol `fail` is already defined } diff --git a/src/test/compile-fail/dupe-symbols-5.rs b/src/test/compile-fail/dupe-symbols-5.rs index 5ca9ca871289e..eb4b50d03ca65 100644 --- a/src/test/compile-fail/dupe-symbols-5.rs +++ b/src/test/compile-fail/dupe-symbols-5.rs @@ -16,5 +16,5 @@ static HELLO: u8 = 0; #[export_name="fail"] pub fn b() { -//~^ symbol `fail` already exists +//~^ symbol `fail` is already defined } diff --git a/src/test/compile-fail/dupe-symbols-6.rs b/src/test/compile-fail/dupe-symbols-6.rs index 9fbc292930ecb..6f412d9a0de15 100644 --- a/src/test/compile-fail/dupe-symbols-6.rs +++ b/src/test/compile-fail/dupe-symbols-6.rs @@ -15,4 +15,4 @@ static HELLO: u8 = 0; #[export_name="fail"] static HELLO_TWICE: u16 = 0; -//~^ symbol `fail` already exists +//~^ symbol `fail` is already defined diff --git a/src/test/compile-fail/dupe-symbols-7.rs b/src/test/compile-fail/dupe-symbols-7.rs index b061f9e257e7d..c2880ba6f51e9 100644 --- a/src/test/compile-fail/dupe-symbols-7.rs +++ b/src/test/compile-fail/dupe-symbols-7.rs @@ -8,14 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -#![crate_type="rlib"] +// error-pattern: entry symbol `main` defined multiple times #![allow(warnings)] -extern { - fn fail(); -} - -#[export_name="fail"] -pub fn a() { -//~^ symbol `fail` already exists -} +#[no_mangle] +fn main(){} diff --git a/src/test/compile-fail/dupe-symbols-8.rs b/src/test/compile-fail/dupe-symbols-8.rs deleted file mode 100644 index c2880ba6f51e9..0000000000000 --- a/src/test/compile-fail/dupe-symbols-8.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 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. -// -// error-pattern: entry symbol `main` defined multiple times -#![allow(warnings)] - -#[no_mangle] -fn main(){} From d8d59a954ff75e7e62088007a70fbd3048db2bf3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 11:46:55 +0200 Subject: [PATCH 12/14] =?UTF-8?q?Address=20Alex=E2=80=99s=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc_trans/trans/base.rs | 11 +++++------ src/librustc_trans/trans/declare.rs | 2 -- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index c7200fc8bb256..0f87af65c7517 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2127,20 +2127,19 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool { /// Create the `main` function which will initialise the rust runtime and call users’ main /// function. pub fn create_entry_wrapper(ccx: &CrateContext, - _sp: Span, + sp: Span, main_llfn: ValueRef) { let et = ccx.sess().entry_type.get().unwrap(); match et { config::EntryMain => { - create_entry_fn(ccx, _sp, main_llfn, true); + create_entry_fn(ccx, sp, main_llfn, true); } - config::EntryStart => create_entry_fn(ccx, _sp, main_llfn, false), + config::EntryStart => create_entry_fn(ccx, sp, main_llfn, false), config::EntryNone => {} // Do nothing. } - #[inline(never)] fn create_entry_fn(ccx: &CrateContext, - _sp: Span, + sp: Span, rust_main: ValueRef, use_start_lang_item: bool) { let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], @@ -2148,7 +2147,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, let llfn = declare::define_cfn(ccx, "main", llfty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ - ccx.sess().span_err(_sp, "entry symbol `main` defined multiple times"); + ccx.sess().span_err(sp, "entry symbol `main` defined multiple times"); // FIXME: We should be smart and show a better diagnostic here. ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead"); ccx.sess().abort_if_errors(); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 147b5161a4ac2..9e7449f670f0f 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -19,8 +19,6 @@ //! ValueRef they return. //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. -#![allow(dead_code)] - use llvm::{self, ValueRef}; use middle::ty::{self, ClosureTyper}; use syntax::abi; From ea04cdfbe86cb4553d0fd26f727728d395013def Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 6 Mar 2015 23:05:11 +0200 Subject: [PATCH 13/14] Remove two cases of unecesary match branches --- src/librustc_trans/trans/attributes.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index a8e9ef98d71d9..2615490a9fbc5 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -189,8 +189,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx match ret_ty.sty { // `~` pointer return values never alias because ownership // is transferred - ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(_) => { + ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => { attrs.ret(llvm::NoAliasAttribute); } _ => {} @@ -199,9 +198,8 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // We can also mark the return value as `dereferenceable` in certain cases match ret_ty.sty { // These are not really pointers but pairs, (pointer, len) - ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { + ty::ty_rptr(_, ty::mt { ty: inner, .. }) + | ty::ty_uniq(inner) if common::type_is_sized(ccx.tcx(), inner) => { let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); attrs.ret(llvm::DereferenceableAttribute(llret_sz)); } From 000db3841e49048c73ba61a0a2480b7878b6807f Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 20 Mar 2015 15:09:00 +0200 Subject: [PATCH 14/14] Rebase fallout --- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/closure.rs | 5 ++++- src/librustc_trans/trans/consts.rs | 2 +- src/librustc_trans/trans/glue.rs | 9 ++++----- src/test/compile-fail/dupe-symbols-4.rs | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 0f87af65c7517..7c51a193b984b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -39,7 +39,7 @@ use middle::astencode; use middle::cfg; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; -use middle::subst::{Subst, Substs}; +use middle::subst::Substs; use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size}; use session::config::{self, NoDebugInfo}; use session::Session; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 60d54cdebeb83..eb4acec25510a 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -386,7 +386,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); - let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name); + let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty) + .unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 336e68f1e8b49..aff5f597bfd9f 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -85,7 +85,7 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) ast::LitBool(b) => C_bool(cx, b), ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()), ast::LitBinary(ref data) => { - addr_of(cx, C_bytes(cx, &data[..]), "binary", e.id) + addr_of(cx, C_bytes(cx, &data[..]), "binary") } } } diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index abcd2882b173e..f974796e69cad 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -30,7 +30,6 @@ use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; -use trans::consts; use trans::datum; use trans::debuginfo::DebugLoc; use trans::declare; @@ -39,8 +38,7 @@ use trans::foreign; use trans::inline; use trans::machine::*; use trans::monomorphize; -use trans::tvec; -use trans::type_of::{type_of, sizing_type_of, align_of}; +use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of}; use trans::type_::Type; use util::ppaux; use util::ppaux::{ty_to_short_str, Repr}; @@ -191,8 +189,9 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val }; let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "drop"); - let llfn = decl_cdecl_fn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())); - note_unique_llvm_symbol(ccx, fn_nm.clone()); + let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm)); + }); ccx.available_drop_glues().borrow_mut().insert(t, fn_nm); let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t))); diff --git a/src/test/compile-fail/dupe-symbols-4.rs b/src/test/compile-fail/dupe-symbols-4.rs index 60e68f72b2437..9e730699d2514 100644 --- a/src/test/compile-fail/dupe-symbols-4.rs +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // +// error-pattern: symbol `fail` is already defined #![crate_type="rlib"] #![allow(warnings)] @@ -27,5 +28,4 @@ impl A for B { impl A for C { #[no_mangle] fn fail(self) {} - //~^ symbol `fail` is already defined }