From 6044f87ee7a23ccc5c7c670afe1e2e44764cd516 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 24 Feb 2015 21:40:05 +0200 Subject: [PATCH 1/4] Validate export_name attribute syntax --- src/librustc_trans/trans/base.rs | 2 +- src/libsyntax/attr.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index b18b7b75d32fc..214562d8216ea 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2710,7 +2710,7 @@ 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(), diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 4fc08c0c2b28c..f09a39592bbf3 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -283,6 +283,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, PartialEq)] pub enum InlineAttr { InlineNone, From d25c1367e32f4834cb537b0ff9ba45640709ad5d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 25 Feb 2015 13:41:03 +0200 Subject: [PATCH 2/4] Properly track functions added to LLVM --- src/librustc_llvm/lib.rs | 3 +++ src/librustc_trans/trans/base.rs | 32 +++++++++-------------------- src/librustc_trans/trans/context.rs | 22 ++++++++++++++------ src/librustc_trans/trans/foreign.rs | 6 +++++- src/librustc_trans/trans/glue.rs | 3 +-- src/rustllvm/RustWrapper.cpp | 5 +++++ 6 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 09a187befb213..fdff20a443e91 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -944,6 +944,9 @@ extern { pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMDeleteFunction(Fn: ValueRef); + pub fn LLVMGetNamedValue(M: ModuleRef, + Name: *const c_char) + -> ValueRef; pub fn LLVMGetOrInsertFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 214562d8216ea..cb9c92de3f80a 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -185,6 +185,7 @@ 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 { + ccx.assert_unique_symbol(name.to_string()); let buf = CString::new(name).unwrap(); let llfn: ValueRef = unsafe { @@ -482,16 +483,6 @@ pub fn unset_split_stack(f: ValueRef) { } } -// 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 get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, t: Ty<'tcx>, @@ -1751,9 +1742,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, @@ -1901,8 +1892,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, @@ -2713,7 +2703,6 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, 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 @@ -2752,15 +2741,14 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let v = match i.node { ast::ItemStatic(_, _, ref expr) => { - // If this static came from an external crate, then - // we need to get the symbol from csearch instead of - // using the current crate's name/version - // information in the hash of the symbol + // If this static came from an external crate, then we need to get the symbol + // from csearch instead of using the current crate's name/version information + // in the hash of the symbol let sym = sym(); debug!("making {}", sym); - // We need the translated value here, because for enums the - // LLVM type is not fully determined by the Rust type. + // We need the translated value here, because for enums the LLVM type is not + // fully determined by the Rust type. let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs); ccx.static_values().borrow_mut().insert(id, v); diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 3586a9dda2067..fed8241784c2d 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -37,6 +37,8 @@ use std::rc::Rc; use syntax::ast; use syntax::parse::token::InternedString; +use libc::c_uint; + pub struct Stats { pub n_static_tydescs: Cell, pub n_glues_created: Cell, @@ -136,7 +138,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, @@ -415,7 +416,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)), @@ -670,10 +670,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,6 +739,20 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &format!("the type `{}` is too big for the current architecture", obj.repr(self.tcx()))) } + + /// Double-check that we never ask LLVM to declare the same symbol twice. LLVM silently mangles + /// such symbols if they have Internal linkage, breaking our linkage model. + // FIXME: this function needs to be used more. Much more. + pub fn assert_unique_symbol<'a>(&'a self, sym: String) { + let buf = CString::new(sym.clone()).unwrap(); + let val = unsafe { llvm::LLVMGetNamedValue(self.llmod(), buf.as_ptr()) }; + if !val.is_null() { + let linkage = unsafe { llvm::LLVMGetLinkage(val) }; + if linkage == llvm::InternalLinkage as c_uint { + self.sess().bug(&format!("duplicate LLVM symbol: {}", sym)); + } + } + } } fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option { diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index efae76c5ef41c..a07ca7220b189 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -622,6 +622,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llwrapfn: ValueRef, tys: &ForeignTypes<'tcx>, t: Ty<'tcx>) { + if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 { + ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \ + multiple functions are being wrapped"); + } + let _icx = push_ctxt( "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn"); let tcx = ccx.tcx(); @@ -641,7 +646,6 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // foo0(&r, NULL, i); // return r; // } - let ptr = "the block\0".as_ptr(); let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, ptr as *const _); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c14683aeade05..7bd98f363b75c 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -518,7 +518,7 @@ pub fn declare_tydesc<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf.as_ptr()) }; - note_unique_llvm_symbol(ccx, name); + ccx.assert_unique_symbol(name.to_string()); let ty_name = token::intern_and_get_ident( &ppaux::ty_to_string(ccx.tcx(), t)); @@ -542,7 +542,6 @@ fn declare_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, t, &format!("glue_{}", name)); let llfn = decl_cdecl_fn(ccx, &fn_nm[..], llfnty, ty::mk_nil(ccx.tcx())); - note_unique_llvm_symbol(ccx, fn_nm.clone()); return (fn_nm, llfn); } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index aaf6d8df29cad..d1c551368c8d5 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -94,6 +94,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 33c03c5c80096a3c9c9e210ef89c4aad32467ce0 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 25 Feb 2015 17:32:23 +0200 Subject: [PATCH 3/4] Error when symbols clash in some scenarios --- src/librustc_llvm/lib.rs | 4 +--- src/librustc_trans/trans/base.rs | 32 +++++++++++++++++++++++------ src/librustc_trans/trans/context.rs | 23 ++++++++++++++++----- src/librustc_trans/trans/foreign.rs | 3 ++- src/test/run-pass/issue-15562.rs | 3 --- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index fdff20a443e91..42fad6d18b7c3 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -925,6 +925,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, @@ -944,9 +945,6 @@ extern { pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMDeleteFunction(Fn: ValueRef); - pub fn LLVMGetNamedValue(M: ModuleRef, - Name: *const c_char) - -> ValueRef; pub fn LLVMGetOrInsertFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index cb9c92de3f80a..6a63be6db83a5 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2745,7 +2745,21 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { // from csearch instead of using the current crate's name/version information // in the hash of the symbol let sym = sym(); - debug!("making {}", sym); + debug!("making static {}", sym); + + // Check whether there’s no symbols with the same name yet. In case there are + // any, we will suffer from the *extern declaration* being renamed if we + // register this static with the same name too. + // FIXME: this doesn’t work reliably anyway. + if ccx.symbol_value(sym.to_string()).is_some() { + ccx.sess().span_fatal(i.span, &format!("symbol {} is already declared", + sym)); + } else if contains_null(&sym[..]) { + // TODO: Should it be a bug? Sounds like prime example for checking + // in parser and attribute getters. + ccx.sess().span_fatal(i.span, &format!("Illegal null byte in export_name \ + value: `{}`", sym)); + } // We need the translated value here, because for enums the LLVM type is not // fully determined by the Rust type. @@ -2760,11 +2774,7 @@ 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()); @@ -2780,6 +2790,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast::ItemFn(_, _, abi, _, _) => { let sym = sym(); + if ccx.symbol_value(sym.to_string()).is_some() { + ccx.sess().span_fatal(i.span, &format!("symbol {} is already declared", + sym)); + } + let llfn = if abi == Rust { register_fn(ccx, i.span, sym, i.id, ty) } else { @@ -2924,6 +2939,11 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, let mty = ty::node_id_to_type(ccx.tcx(), id); let sym = exported_name(ccx, id, mty, &m.attrs); + if ccx.symbol_value(sym.to_string()).is_some() { + ccx.sess().span_fatal(i.span, &format!("symbol {} is already declared", + sym)); + } + if let ty::ty_bare_fn(_, ref f) = mty.sty { let llfn = if f.abi == Rust || f.abi == RustCall { diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index fed8241784c2d..8bab67307c45e 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -740,19 +740,32 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { obj.repr(self.tcx()))) } + /* FIXME?: not sure about placement of these functions */ /// Double-check that we never ask LLVM to declare the same symbol twice. LLVM silently mangles /// such symbols if they have Internal linkage, breaking our linkage model. // FIXME: this function needs to be used more. Much more. pub fn assert_unique_symbol<'a>(&'a self, sym: String) { - let buf = CString::new(sym.clone()).unwrap(); - let val = unsafe { llvm::LLVMGetNamedValue(self.llmod(), buf.as_ptr()) }; - if !val.is_null() { - let linkage = unsafe { llvm::LLVMGetLinkage(val) }; - if linkage == llvm::InternalLinkage as c_uint { + if let Some(v) = self.symbol_value(sym.clone()) { + if (unsafe { llvm::LLVMGetLinkage(v) }) == llvm::InternalLinkage as c_uint { self.sess().bug(&format!("duplicate LLVM symbol: {}", sym)); } } } + + /// Get LLVM value by symbol. + pub fn symbol_value<'a>(&'a self, sym: String) -> Option { + let buf = CString::new(sym.clone()).unwrap(); + let val = unsafe { llvm::LLVMGetNamedValue(self.llmod(), buf.as_ptr()) }; + if val.is_null() { None } else { Some(val) } + } + + /// Returns whether the symbol is defined as opposed to being just declared or not existing at + /// all. + pub fn symbol_defined<'a>(&'a self, sym: String) -> bool { + self.symbol_value(sym).map_or(false, |v| { + unsafe { llvm::LLVMIsDeclaration(v) != 0 } + }) + } } fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option { diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index a07ca7220b189..dd099430f0d3b 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -111,6 +111,7 @@ pub fn register_static(ccx: &CrateContext, let llty = type_of::type_of(ccx, ty); let ident = link_name(foreign_item); + ccx.assert_unique_symbol(ident.to_string()); match attr::first_attr_value_str_by_name(&foreign_item.attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -624,7 +625,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) { if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 { ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \ - multiple functions are being wrapped"); + multiple functions being wrapped"); } let _icx = push_ctxt( diff --git a/src/test/run-pass/issue-15562.rs b/src/test/run-pass/issue-15562.rs index 82f53ea7cd408..e9bb5f86577aa 100644 --- a/src/test/run-pass/issue-15562.rs +++ b/src/test/run-pass/issue-15562.rs @@ -13,9 +13,6 @@ extern crate "issue-15562" as i; pub fn main() { - extern { - fn transmute(); - } unsafe { transmute(); i::transmute(); From 47d07683c7b93f21034d6b6f1eb3d822ade23b0d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 25 Feb 2015 20:56:29 +0200 Subject: [PATCH 4/4] Add tests for duplicate symbol errors --- src/librustc_trans/trans/base.rs | 3 +-- src/test/compile-fail/dupe-symbols-1.rs | 20 +++++++++++++++++ src/test/compile-fail/dupe-symbols-2.rs | 24 ++++++++++++++++++++ src/test/compile-fail/dupe-symbols-3.rs | 20 +++++++++++++++++ src/test/compile-fail/dupe-symbols-4.rs | 30 +++++++++++++++++++++++++ src/test/compile-fail/dupe-symbols-5.rs | 19 ++++++++++++++++ src/test/compile-fail/dupe-symbols-6.rs | 18 +++++++++++++++ src/test/compile-fail/dupe-symbols-7.rs | 20 +++++++++++++++++ 8 files changed, 152 insertions(+), 2 deletions(-) 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 diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 6a63be6db83a5..a6b2f71b38bd1 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2940,8 +2940,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, let sym = exported_name(ccx, id, mty, &m.attrs); if ccx.symbol_value(sym.to_string()).is_some() { - ccx.sess().span_fatal(i.span, &format!("symbol {} is already declared", - sym)); + ccx.sess().span_fatal(m.span, &format!("symbol {} is already declared", sym)); } 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..b663ce47bb6b5 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-1.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"] +pub fn a() { +} + +#[export_name="fail"] +pub fn b() { +//~^ symbol fail is already declared +} 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..d549292dad64a --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -0,0 +1,24 @@ +// 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 is already declared + } +} 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..e1b71e27937a4 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-3.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"] +pub fn a() { +} + +#[no_mangle] +pub fn fail() { +//~^ symbol fail is already declared +} 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..12cc78a245ad0 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -0,0 +1,30 @@ +// 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 is already declared +} 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..fb36755f85002 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-5.rs @@ -0,0 +1,19 @@ +// 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 is already declared +} 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..bcfe1a9b9d8a2 --- /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 is already declared 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..c733e08a9db66 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-7.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)] + +extern { + fn fail(); +} + +#[export_name="fail"] +pub fn a() { +//~^ symbol fail is already declared +}