diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs index 85c0c721114..be7f0ed6a02 100644 --- a/src/librustc_llvm/archive_ro.rs +++ b/src/librustc_llvm/archive_ro.rs @@ -79,14 +79,14 @@ impl Drop for ArchiveRO { } impl<'a> Iterator for Iter<'a> { - type Item = Child<'a>; + type Item = Result, String>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option, String>> { let ptr = unsafe { ::LLVMRustArchiveIteratorNext(self.ptr) }; if ptr.is_null() { - None + ::last_error().map(Err) } else { - Some(Child { ptr: ptr, _data: marker::PhantomData }) + Some(Ok(Child { ptr: ptr, _data: marker::PhantomData })) } } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0bb3ddc9ad1..32009b0f29d 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -56,7 +56,7 @@ pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; pub use self::DLLStorageClassTypes::*; -use std::ffi::CString; +use std::ffi::{CString, CStr}; use std::cell::RefCell; use std::slice; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; @@ -2404,6 +2404,20 @@ pub fn initialize_available_targets() { init_pnacl(); } +pub fn last_error() -> Option { + unsafe { + let cstr = LLVMRustGetLastError(); + if cstr.is_null() { + None + } else { + let err = CStr::from_ptr(cstr).to_bytes(); + let err = String::from_utf8_lossy(err).to_string(); + libc::free(cstr as *mut _); + Some(err) + } + } +} + // The module containing the native LLVM dependencies, generated by the build system // Note that this must come after the rustllvm extern declaration so that // parts of LLVM that rustllvm depends on aren't thrown away by the linker. diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index b0fb12b26b2..07a736d9959 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -729,7 +729,7 @@ pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) { impl ArchiveMetadata { fn new(ar: ArchiveRO) -> Option { let data = { - let section = ar.iter().find(|sect| { + let section = ar.iter().filter_map(|s| s.ok()).find(|sect| { sect.name() == Some(METADATA_FILENAME) }); match section { diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 85060858823..df902fbaff4 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -124,6 +124,7 @@ impl<'a> ArchiveBuilder<'a> { } let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap(); let ret = archive.iter() + .filter_map(|child| child.ok()) .filter(is_relevant_child) .filter_map(|child| child.name()) .filter(|name| !self.removals.iter().any(|x| x == name)) @@ -332,9 +333,15 @@ impl<'a> ArchiveBuilder<'a> { // We skip any files explicitly desired for skipping, and we also skip // all SYMDEF files as these are just magical placeholders which get // re-created when we make a new archive anyway. - for file in archive.iter().filter(is_relevant_child) { + for file in archive.iter() { + let file = try!(file.map_err(string2io)); + if !is_relevant_child(&file) { + continue + } let filename = file.name().unwrap(); - if skip(filename) { continue } + if skip(filename) { + continue + } let filename = Path::new(filename).file_name().unwrap() .to_str().unwrap(); @@ -448,6 +455,7 @@ impl<'a> ArchiveBuilder<'a> { unsafe { if let Some(archive) = self.src_archive() { for child in archive.iter() { + let child = try!(child.map_err(string2io)); let child_name = match child.name() { Some(s) => s, None => continue, @@ -475,10 +483,25 @@ impl<'a> ArchiveBuilder<'a> { strings.push(name); } Addition::Archive { archive, archive_name: _, mut skip } => { - for child in archive.iter().filter(is_relevant_child) { + for child in archive.iter() { + let child = try!(child.map_err(string2io)); + if !is_relevant_child(&child) { + continue + } let child_name = child.name().unwrap(); - if skip(child_name) { continue } + if skip(child_name) { + continue + } + // It appears that LLVM's archive writer is a little + // buggy if the name we pass down isn't just the + // filename component, so chop that off here and + // pass it in. + // + // See LLVM bug 25877 for more info. + let child_name = Path::new(child_name) + .file_name().unwrap() + .to_str().unwrap(); let name = try!(CString::new(child_name)); let m = llvm::LLVMRustArchiveMemberNew(ptr::null(), name.as_ptr(), @@ -517,3 +540,7 @@ impl<'a> ArchiveBuilder<'a> { } } } + +fn string2io(s: String) -> io::Error { + io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s)) +} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 06d32b8f601..649d37e802d 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -52,7 +52,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, link::each_linked_rlib(sess, &mut |_, path| { let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { - child.name().map(|name| (name, child)) + child.ok().and_then(|c| c.name().map(|name| (name, c))) }).filter(|&(name, _)| name.ends_with("bytecode.deflate")); for (name, data) in bytecodes { let bc_encoded = data.data(); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 1068bca55d6..1bbc0a5b04d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -27,24 +27,16 @@ use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; use std::path::{Path, PathBuf}; -use std::ptr; use std::str; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{self, c_uint, c_int, c_void}; +use libc::{c_uint, c_int, c_void}; pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! { - unsafe { - let cstr = llvm::LLVMRustGetLastError(); - if cstr == ptr::null() { - panic!(handler.fatal(&msg[..])); - } else { - let err = CStr::from_ptr(cstr).to_bytes(); - let err = String::from_utf8_lossy(err).to_string(); - libc::free(cstr as *mut _); - panic!(handler.fatal(&format!("{}: {}", &msg[..], &err[..]))); - } + match llvm::last_error() { + Some(err) => panic!(handler.fatal(&format!("{}: {}", msg, err))), + None => panic!(handler.fatal(&msg)), } } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a05135b76e..851ff33cf93 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1271,7 +1271,8 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }; } Variant(_, ref repr, _, _) => { - let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val.val); + let (the_kind, val_opt) = adt::trans_switch(bcx, &repr, + val.val, true); kind = the_kind; if let Some(tval) = val_opt { test_val = tval; } } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 2c11aad8940..ae42134813e 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -890,12 +890,15 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>, /// /// This should ideally be less tightly tied to `_match`. pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - r: &Repr<'tcx>, scrutinee: ValueRef) + r: &Repr<'tcx>, + scrutinee: ValueRef, + range_assert: bool) -> (_match::BranchKind, Option) { match *r { CEnum(..) | General(..) | RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { - (_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None))) + (_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, + range_assert))) } Univariant(..) => { // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants). @@ -916,14 +919,18 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool { /// Obtain the actual discriminant of a value. pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, - scrutinee: ValueRef, cast_to: Option) + scrutinee: ValueRef, cast_to: Option, + range_assert: bool) -> ValueRef { debug!("trans_get_discr r: {:?}", r); let val = match *r { - CEnum(ity, min, max) => load_discr(bcx, ity, scrutinee, min, max), + CEnum(ity, min, max) => { + load_discr(bcx, ity, scrutinee, min, max, range_assert) + } General(ity, ref cases, _) => { let ptr = StructGEP(bcx, scrutinee, 0); - load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1)) + load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1), + range_assert) } Univariant(..) => C_u8(bcx.ccx(), 0), RawNullablePointer { nndiscr, nnty, .. } => { @@ -950,7 +957,8 @@ fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &Disc } /// Helper for cases where the discriminant is simply loaded. -fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr) +fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr, + range_assert: bool) -> ValueRef { let llty = ll_inttype(bcx.ccx(), ity); assert_eq!(val_ty(ptr), llty.ptr_to()); @@ -960,7 +968,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr) let mask = Disr(!0u64 >> (64 - bits)); // For a (max) discr of -1, max will be `-1 as usize`, which overflows. // However, that is fine here (it would still represent the full range), - if max.wrapping_add(Disr(1)) & mask == min & mask { + if max.wrapping_add(Disr(1)) & mask == min & mask || !range_assert { // i.e., if the range is everything. The lo==hi case would be // rejected by the LLVM verifier (it would mean either an // empty set, which is impossible, or the entire range of the @@ -1239,10 +1247,14 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // runtime, so the basic block isn't actually unreachable, so we // need to make it do something with defined behavior. In this case // we just return early from the function. + // + // Note that this is also why the `trans_get_discr` below has + // `false` to indicate that loading the discriminant should + // not have a range assert. let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void"); RetVoid(ret_void_cx, DebugLoc::None); - let discr_val = trans_get_discr(bcx, r, value, None); + let discr_val = trans_get_discr(bcx, r, value, None, false); let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len()); let bcx_next = fcx.new_temp_block("enum-variant-iter-next"); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 7460ef82ebe..9c25284eb60 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -556,7 +556,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, // NB: we must hit the discriminant first so that structural // comparison know not to proceed when the discriminants differ. - match adt::trans_switch(cx, &*repr, av) { + match adt::trans_switch(cx, &*repr, av, false) { (_match::Single, None) => { if n_variants != 0 { assert!(n_variants == 1); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index ada37c5d8df..30cbe6eeee4 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -2116,7 +2116,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let datum = unpack_datum!( bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id)); let llexpr_ptr = datum.to_llref(); - let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx))); + let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, + Some(Type::i64(ccx)), true); ll_t_in = val_ty(discr); (discr, adt::is_discr_signed(&*repr)) } else { diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 0c9b076cb65..629ea6f1c2f 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -655,7 +655,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, match val_ty.sty { ty::TyEnum(..) => { let repr = adt::represent_type(ccx, *val_ty); - adt::trans_get_discr(bcx, &*repr, llargs[0], Some(llret_ty)) + adt::trans_get_discr(bcx, &*repr, llargs[0], + Some(llret_ty), true) } _ => C_null(llret_ty) } diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 852f08a0d34..0dadcf54bf3 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -55,7 +55,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let discr_lvalue = self.trans_lvalue(bcx, discr); let ty = discr_lvalue.ty.to_ty(bcx.tcx()); let repr = adt::represent_type(bcx.ccx(), ty); - let discr = adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, None); + let discr = adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, + None, true); // The else branch of the Switch can't be hit, so branch to an unreachable // instruction so LLVM knows that diff --git a/src/llvm b/src/llvm index 35644395159..de5c31045dc 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 3564439515985dc1cc0d77057ed00901635a80ad +Subproject commit de5c31045dc0f6da1f65d02ee640ccf99ba90e7c diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 2cf6277e057..d3f2907bfc3 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -24,7 +24,13 @@ struct LLVMRustArchiveMember { const char *name; Archive::Child child; - LLVMRustArchiveMember(): filename(NULL), name(NULL), child(NULL, NULL) {} + LLVMRustArchiveMember(): filename(NULL), name(NULL), +#if LLVM_VERSION_MINOR >= 8 + child(NULL, NULL, NULL) +#else + child(NULL, NULL) +#endif + {} ~LLVMRustArchiveMember() {} }; @@ -92,8 +98,18 @@ extern "C" const Archive::Child* LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { if (rai->cur == rai->end) return NULL; - const Archive::Child *cur = rai->cur.operator->(); - Archive::Child *ret = new Archive::Child(*cur); +#if LLVM_VERSION_MINOR >= 8 + const ErrorOr* cur = rai->cur.operator->(); + if (!*cur) { + LLVMRustSetLastError(cur->getError().message().c_str()); + return NULL; + } + const Archive::Child &child = cur->get(); +#else + const Archive::Child &child = *rai->cur.operator->(); +#endif + Archive::Child *ret = new Archive::Child(child); + ++rai->cur; return ret; } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5a9c096e5f5..a625a75933d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -348,6 +348,19 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( LLVMValueRef Fn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) { +#if LLVM_VERSION_MINOR >= 8 + DITemplateParameterArray TParams = + DITemplateParameterArray(unwrap(TParam)); + DISubprogram *Sub = Builder->createFunction( + unwrapDI(Scope), Name, LinkageName, + unwrapDI(File), LineNo, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + Flags, isOptimized, + TParams, + unwrapDIptr(Decl)); + unwrap(Fn)->setSubprogram(Sub); + return wrap(Sub); +#else return wrap(Builder->createFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, @@ -356,6 +369,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( unwrap(Fn), unwrapDIptr(TParam), unwrapDIptr(Decl))); +#endif } extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( @@ -830,7 +844,9 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { #if LLVM_VERSION_MINOR >= 6 raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_MINOR >= 7 +#if LLVM_VERSION_MINOR >= 8 + if (Linker::linkModules(*Dst, std::move(Src.get()))) { +#elif LLVM_VERSION_MINOR >= 7 if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { #else if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) { diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 4ef1fbb506b..7df7df505cd 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2015-12-02 +2015-01-25 diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json index d7cf7131d73..e3080d29ec3 100644 --- a/src/test/run-make/target-specs/my-awesome-platform.json +++ b/src/test/run-make/target-specs/my-awesome-platform.json @@ -1,5 +1,4 @@ { - "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "32",