-Version 1.15.1 (2017-02-08)
+Version 1.15.1 (2017-02-09)
===========================
* [Fix IntoIter::as_mut_slice's signature][39466]
+* [Compile compiler builtins with `-fPIC` on 32-bit platforms][39523]
[39466]: https://github.com/rust-lang/rust/pull/39466
+[39523]: https://github.com/rust-lang/rust/pull/39523
Version 1.15.0 (2017-02-02)
"rustc_incremental 0.0.0",
"rustc_llvm 0.0.0",
"rustc_platform_intrinsics 0.0.0",
+ "serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
}
}
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
+ fn from(slice: &'a [T]) -> Box<[T]> {
+ let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() };
+ boxed.copy_from_slice(slice);
+ boxed
+ }
+}
+
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl<'a> From<&'a str> for Box<str> {
+ fn from(s: &'a str) -> Box<str> {
+ let boxed: Box<[u8]> = Box::from(s.as_bytes());
+ unsafe { mem::transmute(boxed) }
+ }
+}
+
impl Box<Any> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
use core::ops::Deref;
use core::result::Result::{Err, Ok};
use core::clone::Clone;
+use core::f64;
+use core::i64;
use std::boxed::Box;
assert_eq!(19, y.get());
}
}
+
+#[test]
+fn f64_slice() {
+ let slice: &[f64] = &[-1.0, 0.0, 1.0, f64::INFINITY];
+ let boxed: Box<[f64]> = Box::from(slice);
+ assert_eq!(&*boxed, slice)
+}
+
+#[test]
+fn i64_slice() {
+ let slice: &[i64] = &[i64::MIN, -2, -1, 0, 1, 2, i64::MAX];
+ let boxed: Box<[i64]> = Box::from(slice);
+ assert_eq!(&*boxed, slice)
+}
+
+#[test]
+fn str_slice() {
+ let s = "Hello, world!";
+ let boxed: Box<str> = Box::from(s);
+ assert_eq!(&*boxed, s)
+}
/// Reserves capacity for at least `additional` more elements to be inserted
/// in the given `Vec<T>`. The collection may reserve more space to avoid
- /// frequent reallocations.
+ /// frequent reallocations. After calling `reserve`, capacity will be
+ /// greater than or equal to `self.len() + additional`. Does nothing if
+ /// capacity is already sufficient.
///
/// # Panics
///
}
/// Reserves the minimum capacity for exactly `additional` more elements to
- /// be inserted in the given `Vec<T>`. Does nothing if the capacity is already
- /// sufficient.
+ /// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
+ /// capacity will be greater than or equal to `self.len() + additional`.
+ /// Does nothing if the capacity is already sufficient.
///
/// Note that the allocator may give the collection more space than it
/// requests. Therefore capacity can not be relied upon to be precisely
/// Returns the `n`th element of the iterator.
///
- /// Note that all preceding elements will be consumed (i.e. discarded).
- ///
/// Like most indexing operations, the count starts from zero, so `nth(0)`
/// returns the first value, `nth(1)` the second, and so on.
///
+ /// Note that all preceding elements, as well as the returned element, will be
+ /// consumed from the iterator. That means that the preceding elements will be
+ /// discarded, and also that calling `nth(0)` multiple times on the same iterator
+ /// will return different elements.
+ ///
/// `nth()` will return [`None`] if `n` is greater than or equal to the length of the
/// iterator.
///
rustc_incremental = { path = "../librustc_incremental" }
rustc_llvm = { path = "../librustc_llvm" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
+serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
cmd.arg(root.join(obj));
}
- if sess.target.target.options.is_like_emscripten &&
- sess.panic_strategy() == PanicStrategy::Abort {
- cmd.args(&["-s", "DISABLE_EXCEPTION_CATCHING=1"]);
+ if sess.target.target.options.is_like_emscripten {
+ cmd.arg("-s");
+ cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
+ "DISABLE_EXCEPTION_CATCHING=1"
+ } else {
+ "DISABLE_EXCEPTION_CATCHING=0"
+ });
}
{
// If we're building a dynamic library then some platforms need to make sure
// that all symbols are exported correctly from the dynamic library.
- if crate_type != config::CrateTypeExecutable {
+ if crate_type != config::CrateTypeExecutable ||
+ sess.target.target.options.is_like_emscripten {
cmd.export_symbols(tmpdir, crate_type);
}
use middle::dependency_format::Linkage;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use session::Session;
-use session::config::CrateType;
-use session::config;
+use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
+use serialize::{json, Encoder};
/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
sess: sess,
info: self
}) as Box<Linker>
+ } else if sess.target.target.options.is_like_emscripten {
+ Box::new(EmLinker {
+ cmd: cmd,
+ sess: sess,
+ info: self
+ }) as Box<Linker>
} else {
Box::new(GnuLinker {
cmd: cmd,
}
}
+pub struct EmLinker<'a> {
+ cmd: &'a mut Command,
+ sess: &'a Session,
+ info: &'a LinkerInfo
+}
+
+impl<'a> Linker for EmLinker<'a> {
+ fn include_path(&mut self, path: &Path) {
+ self.cmd.arg("-L").arg(path);
+ }
+
+ fn link_staticlib(&mut self, lib: &str) {
+ self.cmd.arg("-l").arg(lib);
+ }
+
+ fn output_filename(&mut self, path: &Path) {
+ self.cmd.arg("-o").arg(path);
+ }
+
+ fn add_object(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn link_dylib(&mut self, lib: &str) {
+ // Emscripten always links statically
+ self.link_staticlib(lib);
+ }
+
+ fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
+ // not supported?
+ self.link_staticlib(lib);
+ }
+
+ fn link_whole_rlib(&mut self, lib: &Path) {
+ // not supported?
+ self.link_rlib(lib);
+ }
+
+ fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+ self.link_dylib(lib);
+ }
+
+ fn link_rlib(&mut self, lib: &Path) {
+ self.add_object(lib);
+ }
+
+ fn position_independent_executable(&mut self) {
+ // noop
+ }
+
+ fn args(&mut self, args: &[String]) {
+ self.cmd.args(args);
+ }
+
+ fn framework_path(&mut self, _path: &Path) {
+ bug!("frameworks are not supported on Emscripten")
+ }
+
+ fn link_framework(&mut self, _framework: &str) {
+ bug!("frameworks are not supported on Emscripten")
+ }
+
+ fn gc_sections(&mut self, _keep_metadata: bool) {
+ // noop
+ }
+
+ fn optimize(&mut self) {
+ // Emscripten performs own optimizations
+ self.cmd.arg(match self.sess.opts.optimize {
+ OptLevel::No => "-O0",
+ OptLevel::Less => "-O1",
+ OptLevel::Default => "-O2",
+ OptLevel::Aggressive => "-O3",
+ OptLevel::Size => "-Os",
+ OptLevel::SizeMin => "-Oz"
+ });
+ // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
+ self.cmd.args(&["--memory-init-file", "0"]);
+ }
+
+ fn debuginfo(&mut self) {
+ // Preserve names or generate source maps depending on debug info
+ self.cmd.arg(match self.sess.opts.debuginfo {
+ DebugInfoLevel::NoDebugInfo => "-g0",
+ DebugInfoLevel::LimitedDebugInfo => "-g3",
+ DebugInfoLevel::FullDebugInfo => "-g4"
+ });
+ }
+
+ fn no_default_libraries(&mut self) {
+ self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
+ }
+
+ fn build_dylib(&mut self, _out_filename: &Path) {
+ bug!("building dynamic library is unsupported on Emscripten")
+ }
+
+ fn whole_archives(&mut self) {
+ // noop
+ }
+
+ fn no_whole_archives(&mut self) {
+ // noop
+ }
+
+ fn hint_static(&mut self) {
+ // noop
+ }
+
+ fn hint_dynamic(&mut self) {
+ // noop
+ }
+
+ fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
+ let symbols = &self.info.exports[&crate_type];
+
+ debug!("EXPORTED SYMBOLS:");
+
+ self.cmd.arg("-s");
+
+ let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
+ let mut encoded = String::new();
+
+ {
+ let mut encoder = json::Encoder::new(&mut encoded);
+ let res = encoder.emit_seq(symbols.len(), |encoder| {
+ for (i, sym) in symbols.iter().enumerate() {
+ encoder.emit_seq_elt(i, |encoder| {
+ encoder.emit_str(&("_".to_string() + sym))
+ })?;
+ }
+ Ok(())
+ });
+ if let Err(e) = res {
+ self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
+ }
+ }
+ debug!("{}", encoded);
+ arg.push(encoded);
+
+ self.cmd.arg(arg);
+ }
+
+ fn subsystem(&mut self, _subsystem: &str) {
+ // noop
+ }
+}
+
fn exported_symbols(scx: &SharedCrateContext,
exported_symbols: &ExportedSymbols,
crate_type: CrateType)
#[macro_use] extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
+extern crate serialize;
pub use rustc::session;
pub use rustc::middle;
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
+#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
- struct Data<F, R> {
+ #[allow(unions_with_drop_fields)]
+ union Data<F, R> {
f: F,
r: R,
}
// We do some sketchy operations with ownership here for the sake of
- // performance. The `Data` structure is never actually fully valid, but
- // instead it always contains at least one uninitialized field. We can only
- // pass pointers down to `__rust_maybe_catch_panic` (can't pass objects by
- // value), so we do all the ownership tracking here manully.
+ // performance. We can only pass pointers down to
+ // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all
+ // the ownership tracking here manually using a union.
//
- // Note that this is all invalid if any of these functions unwind, but the
- // whole point of this function is to prevent that! As a result we go
- // through a transition where:
+ // We go through a transition where:
//
- // * First, only the closure we're going to call is initialized. The return
- // value is uninitialized.
+ // * First, we set the data to be the closure that we're going to call.
// * When we make the function call, the `do_call` function below, we take
- // ownership of the function pointer, replacing it with uninitialized
- // data. At this point the `Data` structure is entirely uninitialized, but
- // it won't drop due to an unwind because it's owned on the other side of
- // the catch panic.
+ // ownership of the function pointer. At this point the `Data` union is
+ // entirely uninitialized.
// * If the closure successfully returns, we write the return value into the
// data's return slot. Note that `ptr::write` is used as it's overwriting
// uninitialized data.
// in one of two states:
//
// 1. The closure didn't panic, in which case the return value was
- // filled in. We have to be careful to `forget` the closure,
- // however, as ownership was passed to the `do_call` function.
+ // filled in. We move it out of `data` and return it.
// 2. The closure panicked, in which case the return value wasn't
- // filled in. In this case the entire `data` structure is invalid,
- // so we forget the entire thing.
+ // filled in. In this case the entire `data` union is invalid, so
+ // there is no need to drop anything.
//
// Once we stack all that together we should have the "most efficient'
// method of calling a catch panic whilst juggling ownership.
let mut any_vtable = 0;
let mut data = Data {
f: f,
- r: mem::uninitialized(),
};
let r = __rust_maybe_catch_panic(do_call::<F, R>,
&mut any_vtable);
return if r == 0 {
- let Data { f, r } = data;
- mem::forget(f);
debug_assert!(update_panic_count(0) == 0);
- Ok(r)
+ Ok(data.r)
} else {
- mem::forget(data);
update_panic_count(-1);
debug_assert!(update_panic_count(0) == 0);
Err(mem::transmute(raw::TraitObject {
--- /dev/null
+// Copyright 2017 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.
+
+fn worker() -> ! {
+ panic!()
+}
+
+fn main() {
+ std::panic::catch_unwind(worker).unwrap_err();
+}
a: T
}
-#[repr(packed)]
-struct Packed<T: ?Sized> {
- a: u8,
- b: T
-}
-
struct HasDrop<T: ?Sized> {
ptr: Box<usize>,
data: T
// The pointers should be the same
assert_eq!(ptr1, ptr2);
- // Test that packed structs are handled correctly
- let p : Packed<usize> = Packed { a: 0, b: 13 };
- assert_eq!(p.b.get(), 13);
- let p : &Packed<Bar> = &p;
- assert_eq!(p.b.get(), 13);
-
// Test that nested DSTs work properly
let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
assert_eq!(f.b.b.get(), 17);
// and wrap it up in a `Value::Table`.
let mut manifest = BTreeMap::new();
manifest.insert("manifest-version".to_string(),
- toml::encode(&manifest_version));
- manifest.insert("date".to_string(), toml::encode(&date));
+ toml::Value::String(manifest_version));
+ manifest.insert("date".to_string(), toml::Value::String(date));
manifest.insert("pkg".to_string(), toml::encode(&pkg));
let manifest = toml::Value::Table(manifest).to_string();
fn hash(&self, path: &Path) -> String {
let sha = t!(Command::new("shasum")
.arg("-a").arg("256")
- .arg(path)
+ .arg(path.file_name().unwrap())
+ .current_dir(path.parent().unwrap())
.output());
assert!(sha.status.success());