Skip to content

Commit d1cace1

Browse files
committed
trans: Upgrade LLVM
This brings some routine upgrades to the bundled LLVM that we're using, the most notable of which is a bug fix to the way we handle range asserts when loading the discriminant of an enum. This fix ended up being very similar to f9d4149 where we basically can't have a range assert when loading a discriminant due to filling drop, and appropriate flags were added to communicate this to `trans::adt`.
1 parent 142214d commit d1cace1

File tree

17 files changed

+124
-44
lines changed

17 files changed

+124
-44
lines changed

src/librustc_llvm/archive_ro.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ impl Drop for ArchiveRO {
7979
}
8080

8181
impl<'a> Iterator for Iter<'a> {
82-
type Item = Child<'a>;
82+
type Item = Result<Child<'a>, String>;
8383

84-
fn next(&mut self) -> Option<Child<'a>> {
84+
fn next(&mut self) -> Option<Result<Child<'a>, String>> {
8585
let ptr = unsafe { ::LLVMRustArchiveIteratorNext(self.ptr) };
8686
if ptr.is_null() {
87-
None
87+
::last_error().map(Err)
8888
} else {
89-
Some(Child { ptr: ptr, _data: marker::PhantomData })
89+
Some(Ok(Child { ptr: ptr, _data: marker::PhantomData }))
9090
}
9191
}
9292
}

src/librustc_llvm/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub use self::DiagnosticSeverity::*;
5656
pub use self::Linkage::*;
5757
pub use self::DLLStorageClassTypes::*;
5858

59-
use std::ffi::CString;
59+
use std::ffi::{CString, CStr};
6060
use std::cell::RefCell;
6161
use std::slice;
6262
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
@@ -2404,6 +2404,20 @@ pub fn initialize_available_targets() {
24042404
init_pnacl();
24052405
}
24062406

2407+
pub fn last_error() -> Option<String> {
2408+
unsafe {
2409+
let cstr = LLVMRustGetLastError();
2410+
if cstr.is_null() {
2411+
None
2412+
} else {
2413+
let err = CStr::from_ptr(cstr).to_bytes();
2414+
let err = String::from_utf8_lossy(err).to_string();
2415+
libc::free(cstr as *mut _);
2416+
Some(err)
2417+
}
2418+
}
2419+
}
2420+
24072421
// The module containing the native LLVM dependencies, generated by the build system
24082422
// Note that this must come after the rustllvm extern declaration so that
24092423
// parts of LLVM that rustllvm depends on aren't thrown away by the linker.

src/librustc_metadata/loader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) {
729729
impl ArchiveMetadata {
730730
fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
731731
let data = {
732-
let section = ar.iter().find(|sect| {
732+
let section = ar.iter().filter_map(|s| s.ok()).find(|sect| {
733733
sect.name() == Some(METADATA_FILENAME)
734734
});
735735
match section {

src/librustc_trans/back/archive.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ impl<'a> ArchiveBuilder<'a> {
124124
}
125125
let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
126126
let ret = archive.iter()
127+
.filter_map(|child| child.ok())
127128
.filter(is_relevant_child)
128129
.filter_map(|child| child.name())
129130
.filter(|name| !self.removals.iter().any(|x| x == name))
@@ -332,9 +333,15 @@ impl<'a> ArchiveBuilder<'a> {
332333
// We skip any files explicitly desired for skipping, and we also skip
333334
// all SYMDEF files as these are just magical placeholders which get
334335
// re-created when we make a new archive anyway.
335-
for file in archive.iter().filter(is_relevant_child) {
336+
for file in archive.iter() {
337+
let file = try!(file.map_err(string2io));
338+
if !is_relevant_child(&file) {
339+
continue
340+
}
336341
let filename = file.name().unwrap();
337-
if skip(filename) { continue }
342+
if skip(filename) {
343+
continue
344+
}
338345
let filename = Path::new(filename).file_name().unwrap()
339346
.to_str().unwrap();
340347

@@ -448,6 +455,7 @@ impl<'a> ArchiveBuilder<'a> {
448455
unsafe {
449456
if let Some(archive) = self.src_archive() {
450457
for child in archive.iter() {
458+
let child = try!(child.map_err(string2io));
451459
let child_name = match child.name() {
452460
Some(s) => s,
453461
None => continue,
@@ -475,10 +483,25 @@ impl<'a> ArchiveBuilder<'a> {
475483
strings.push(name);
476484
}
477485
Addition::Archive { archive, archive_name: _, mut skip } => {
478-
for child in archive.iter().filter(is_relevant_child) {
486+
for child in archive.iter() {
487+
let child = try!(child.map_err(string2io));
488+
if !is_relevant_child(&child) {
489+
continue
490+
}
479491
let child_name = child.name().unwrap();
480-
if skip(child_name) { continue }
481-
492+
if skip(child_name) {
493+
continue
494+
}
495+
496+
// It appears that LLVM's archive writer is a little
497+
// buggy if the name we pass down isn't just the
498+
// filename component, so chop that off here and
499+
// pass it in.
500+
//
501+
// See LLVM bug 25877 for more info.
502+
let child_name = Path::new(child_name)
503+
.file_name().unwrap()
504+
.to_str().unwrap();
482505
let name = try!(CString::new(child_name));
483506
let m = llvm::LLVMRustArchiveMemberNew(ptr::null(),
484507
name.as_ptr(),
@@ -517,3 +540,7 @@ impl<'a> ArchiveBuilder<'a> {
517540
}
518541
}
519542
}
543+
544+
fn string2io(s: String) -> io::Error {
545+
io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
546+
}

src/librustc_trans/back/lto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
5252
link::each_linked_rlib(sess, &mut |_, path| {
5353
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
5454
let bytecodes = archive.iter().filter_map(|child| {
55-
child.name().map(|name| (name, child))
55+
child.ok().and_then(|c| c.name().map(|name| (name, c)))
5656
}).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
5757
for (name, data) in bytecodes {
5858
let bc_encoded = data.data();

src/librustc_trans/back/write.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,16 @@ use std::collections::HashMap;
2727
use std::ffi::{CStr, CString};
2828
use std::fs;
2929
use std::path::{Path, PathBuf};
30-
use std::ptr;
3130
use std::str;
3231
use std::sync::{Arc, Mutex};
3332
use std::sync::mpsc::channel;
3433
use std::thread;
35-
use libc::{self, c_uint, c_int, c_void};
34+
use libc::{c_uint, c_int, c_void};
3635

3736
pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! {
38-
unsafe {
39-
let cstr = llvm::LLVMRustGetLastError();
40-
if cstr == ptr::null() {
41-
panic!(handler.fatal(&msg[..]));
42-
} else {
43-
let err = CStr::from_ptr(cstr).to_bytes();
44-
let err = String::from_utf8_lossy(err).to_string();
45-
libc::free(cstr as *mut _);
46-
panic!(handler.fatal(&format!("{}: {}", &msg[..], &err[..])));
47-
}
37+
match llvm::last_error() {
38+
Some(err) => panic!(handler.fatal(&format!("{}: {}", msg, err))),
39+
None => panic!(handler.fatal(&msg)),
4840
}
4941
}
5042

src/librustc_trans/trans/_match.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,8 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
12711271
};
12721272
}
12731273
Variant(_, ref repr, _, _) => {
1274-
let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val.val);
1274+
let (the_kind, val_opt) = adt::trans_switch(bcx, &repr,
1275+
val.val, true);
12751276
kind = the_kind;
12761277
if let Some(tval) = val_opt { test_val = tval; }
12771278
}

src/librustc_trans/trans/adt.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -890,12 +890,15 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
890890
///
891891
/// This should ideally be less tightly tied to `_match`.
892892
pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
893-
r: &Repr<'tcx>, scrutinee: ValueRef)
893+
r: &Repr<'tcx>,
894+
scrutinee: ValueRef,
895+
range_assert: bool)
894896
-> (_match::BranchKind, Option<ValueRef>) {
895897
match *r {
896898
CEnum(..) | General(..) |
897899
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
898-
(_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
900+
(_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None,
901+
range_assert)))
899902
}
900903
Univariant(..) => {
901904
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
@@ -916,14 +919,18 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
916919

917920
/// Obtain the actual discriminant of a value.
918921
pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
919-
scrutinee: ValueRef, cast_to: Option<Type>)
922+
scrutinee: ValueRef, cast_to: Option<Type>,
923+
range_assert: bool)
920924
-> ValueRef {
921925
debug!("trans_get_discr r: {:?}", r);
922926
let val = match *r {
923-
CEnum(ity, min, max) => load_discr(bcx, ity, scrutinee, min, max),
927+
CEnum(ity, min, max) => {
928+
load_discr(bcx, ity, scrutinee, min, max, range_assert)
929+
}
924930
General(ity, ref cases, _) => {
925931
let ptr = StructGEP(bcx, scrutinee, 0);
926-
load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1))
932+
load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
933+
range_assert)
927934
}
928935
Univariant(..) => C_u8(bcx.ccx(), 0),
929936
RawNullablePointer { nndiscr, nnty, .. } => {
@@ -950,7 +957,8 @@ fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &Disc
950957
}
951958

952959
/// Helper for cases where the discriminant is simply loaded.
953-
fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
960+
fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr,
961+
range_assert: bool)
954962
-> ValueRef {
955963
let llty = ll_inttype(bcx.ccx(), ity);
956964
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)
960968
let mask = Disr(!0u64 >> (64 - bits));
961969
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
962970
// However, that is fine here (it would still represent the full range),
963-
if max.wrapping_add(Disr(1)) & mask == min & mask {
971+
if max.wrapping_add(Disr(1)) & mask == min & mask || !range_assert {
964972
// i.e., if the range is everything. The lo==hi case would be
965973
// rejected by the LLVM verifier (it would mean either an
966974
// 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>,
12391247
// runtime, so the basic block isn't actually unreachable, so we
12401248
// need to make it do something with defined behavior. In this case
12411249
// we just return early from the function.
1250+
//
1251+
// Note that this is also why the `trans_get_discr` below has
1252+
// `false` to indicate that loading the discriminant should
1253+
// not have a range assert.
12421254
let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void");
12431255
RetVoid(ret_void_cx, DebugLoc::None);
12441256

1245-
let discr_val = trans_get_discr(bcx, r, value, None);
1257+
let discr_val = trans_get_discr(bcx, r, value, None, false);
12461258
let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len());
12471259
let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
12481260

src/librustc_trans/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
556556
// NB: we must hit the discriminant first so that structural
557557
// comparison know not to proceed when the discriminants differ.
558558

559-
match adt::trans_switch(cx, &*repr, av) {
559+
match adt::trans_switch(cx, &*repr, av, false) {
560560
(_match::Single, None) => {
561561
if n_variants != 0 {
562562
assert!(n_variants == 1);

src/librustc_trans/trans/expr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2116,7 +2116,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
21162116
let datum = unpack_datum!(
21172117
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
21182118
let llexpr_ptr = datum.to_llref();
2119-
let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
2119+
let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr,
2120+
Some(Type::i64(ccx)), true);
21202121
ll_t_in = val_ty(discr);
21212122
(discr, adt::is_discr_signed(&*repr))
21222123
} else {

0 commit comments

Comments
 (0)