Skip to content

Commit

Permalink
Merge pull request #28802 from alexcrichton/beta-backport
Browse files Browse the repository at this point in the history
Backporting accepted PRs to beta
  • Loading branch information
brson committed Oct 2, 2015
2 parents d2e13e8 + 773cf0f commit ae94d18
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 32 deletions.
41 changes: 40 additions & 1 deletion src/libcollections/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -83,7 +86,12 @@ impl<T> VecDeque<T> {
/// Marginally more convenient
#[inline]
fn cap(&self) -> usize {
self.buf.cap()
if mem::size_of::<T>() == 0 {
// For zero sized types, we are always at maximum capacity
MAXIMUM_ZST_CAPACITY
} else {
self.buf.cap()
}
}

/// Turn ptr into a slice
Expand Down Expand Up @@ -1465,6 +1473,7 @@ impl<T: Clone> VecDeque<T> {
#[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)
}

Expand Down Expand Up @@ -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();
}
}
}
}
108 changes: 77 additions & 31 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())) {
Expand Down Expand Up @@ -2623,28 +2609,83 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
}
}
}
}

// Create a `__imp_<symbol> = &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<ValueRef> {
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<ValueRef> {
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,
}
}
}
Expand Down Expand Up @@ -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(),
Expand Down
15 changes: 15 additions & 0 deletions src/test/auxiliary/msvc-data-only-lib.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
17 changes: 17 additions & 0 deletions src/test/run-pass/msvc-data-only.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

0 comments on commit ae94d18

Please sign in to comment.