diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index b6bf0669d0ff1..4ee9787c9ec8a 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -21,9 +21,11 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator}; +use core::mem; use core::ops::{Index, IndexMut}; use core::ptr; use core::slice; +use core::usize; use core::hash::{Hash, Hasher}; use core::cmp; @@ -32,6 +34,7 @@ use alloc::raw_vec::RawVec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 +const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two /// `VecDeque` is a growable ring buffer, which can be used as a /// double-ended queue efficiently. @@ -83,7 +86,12 @@ impl VecDeque { /// Marginally more convenient #[inline] fn cap(&self) -> usize { - self.buf.cap() + if mem::size_of::() == 0 { + // For zero sized types, we are always at maximum capacity + MAXIMUM_ZST_CAPACITY + } else { + self.buf.cap() + } } /// Turn ptr into a slice @@ -1465,6 +1473,7 @@ impl VecDeque { #[inline] fn wrap_index(index: usize, size: usize) -> usize { // size is always a power of 2 + debug_assert!(size.is_power_of_two()); index & (size - 1) } @@ -2032,4 +2041,34 @@ mod tests { } } } + + #[test] + fn test_zst_push() { + const N: usize = 8; + + // Zero sized type + struct Zst; + + // Test that for all possible sequences of push_front / push_back, + // we end up with a deque of the correct size + + for len in 0..N { + let mut tester = VecDeque::with_capacity(len); + assert_eq!(tester.len(), 0); + assert!(tester.capacity() >= len); + for case in 0..(1 << len) { + assert_eq!(tester.len(), 0); + for bit in 0..len { + if case & (1 << bit) != 0 { + tester.push_front(Zst); + } else { + tester.push_back(Zst); + } + } + assert_eq!(tester.len(), len); + assert_eq!(tester.iter().count(), len); + tester.clear(); + } + } + } } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1359252e0351a..79484ad3ddd56 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2570,20 +2570,6 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { unsafe { let mut declared = HashSet::new(); - let iter_globals = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstGlobal(llmod), - step: llvm::LLVMGetNextGlobal, - } - }; - - let iter_functions = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstFunction(llmod), - step: llvm::LLVMGetNextFunction, - } - }; - // Collect all external declarations in all compilation units. for ccx in cx.iter() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { @@ -2623,28 +2609,83 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { } } } +} + +// Create a `__imp_ = &symbol` global for every public static `symbol`. +// This is required to satisfy `dllimport` references to static data in .rlibs +// when using MSVC linker. We do this only for data, as linker can fix up +// code references on its own. +// See #26591, #27438 +fn create_imps(cx: &SharedCrateContext) { + // The x86 ABI seems to require that leading underscores are added to symbol + // names, so we need an extra underscore on 32-bit. There's also a leading + // '\x01' here which disables LLVM's symbol mangling (e.g. no extra + // underscores added in front). + let prefix = if cx.sess().target.target.target_pointer_width == "32" { + "\x01__imp__" + } else { + "\x01__imp_" + }; + unsafe { + for ccx in cx.iter() { + let exported: Vec<_> = iter_globals(ccx.llmod()) + .filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && + llvm::LLVMIsDeclaration(val) == 0) + .collect(); + + let i8p_ty = Type::i8p(&ccx); + for val in exported { + let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let mut imp_name = prefix.as_bytes().to_vec(); + imp_name.extend(name.to_bytes()); + let imp_name = CString::new(imp_name).unwrap(); + let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(), + imp_name.as_ptr() as *const _); + let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); + llvm::LLVMSetInitializer(imp, init); + llvm::SetLinkage(imp, llvm::ExternalLinkage); + } + } + } +} +struct ValueIter { + cur: ValueRef, + step: unsafe extern "C" fn(ValueRef) -> ValueRef, +} + +impl Iterator for ValueIter { + type Item = ValueRef; - struct ValueIter { - cur: ValueRef, - step: unsafe extern "C" fn(ValueRef) -> ValueRef, + fn next(&mut self) -> Option { + let old = self.cur; + if !old.is_null() { + self.cur = unsafe { + let step: unsafe extern "C" fn(ValueRef) -> ValueRef = + mem::transmute_copy(&self.step); + step(old) + }; + Some(old) + } else { + None + } } +} - impl Iterator for ValueIter { - type Item = ValueRef; +fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstGlobal(llmod), + step: llvm::LLVMGetNextGlobal, + } + } +} - fn next(&mut self) -> Option { - let old = self.cur; - if !old.is_null() { - self.cur = unsafe { - let step: unsafe extern "C" fn(ValueRef) -> ValueRef = - mem::transmute_copy(&self.step); - step(old) - }; - Some(old) - } else { - None - } +fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstFunction(llmod), + step: llvm::LLVMGetNextFunction, } } } @@ -2824,6 +2865,11 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat &reachable_symbols.iter().map(|x| &x[..]).collect()); } + if sess.target.target.options.is_like_msvc && + sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { + create_imps(&shared_ccx); + } + let metadata_module = ModuleTranslation { llcx: shared_ccx.metadata_llcx(), llmod: shared_ccx.metadata_llmod(), diff --git a/src/test/auxiliary/msvc-data-only-lib.rs b/src/test/auxiliary/msvc-data-only-lib.rs new file mode 100644 index 0000000000000..71fb9a519489b --- /dev/null +++ b/src/test/auxiliary/msvc-data-only-lib.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. + +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub static FOO: i32 = 42; diff --git a/src/test/run-pass/msvc-data-only.rs b/src/test/run-pass/msvc-data-only.rs new file mode 100644 index 0000000000000..ad6888c4d3096 --- /dev/null +++ b/src/test/run-pass/msvc-data-only.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:msvc-data-only-lib.rs + +extern crate msvc_data_only_lib; + +fn main() { + println!("The answer is {} !", msvc_data_only_lib::FOO); +}