opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
-opt rpath 0 "build rpaths into rustc itself"
+opt rpath 1 "build rpaths into rustc itself"
opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
# This is used by the automation to produce single-target nightlies
opt dist-host-only 0 "only install bins for the host architecture"
DEPS_rustc_unicode := core
DEPS_std := core libc rand alloc collections rustc_unicode \
- native:rust_builtin native:backtrace \
+ native:backtrace \
alloc_system
DEPS_arena := std
DEPS_glob := std
# that's per-target so you're allowed to conditionally add files based on the
# target.
################################################################################
-NATIVE_LIBS := rust_builtin hoedown miniz rust_test_helpers
+NATIVE_LIBS := hoedown miniz rust_test_helpers
# $(1) is the target triple
define NATIVE_LIBRARIES
hoedown/src/stack.c \
hoedown/src/version.c
NATIVE_DEPS_miniz_$(1) = miniz.c
-NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
- rust_android_dummy.c
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
################################################################################
let flags = align_to_flags(align);
unsafe { je_nallocx(size as size_t, flags) as usize }
}
+
+// These symbols are used by jemalloc on android but the really old android
+// we're building on doesn't have them defined, so just make sure the symbols
+// are available.
+#[no_mangle]
+#[cfg(target_os = "android")]
+pub extern fn pthread_atfork(_prefork: *mut u8,
+ _postfork_parent: *mut u8,
+ _postfork_child: *mut u8) -> i32 {
+ 0
+}
"windows" | "unix" => ret.push(attr::mk_word_item(fam)),
_ => (),
}
+ if sess.target.target.options.has_elf_tls {
+ ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
+ }
if sess.opts.debug_assertions {
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
}
use target::Target;
pub fn target() -> Target {
- let base = super::linux_base::opts();
+ let mut base = super::linux_base::opts();
+ base.has_elf_tls = false;
Target {
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::env;
+
use target::TargetOptions;
-use std::default::Default;
pub fn opts() -> TargetOptions {
+ // ELF TLS is only available in OSX 10.7+. If you try to compile for 10.6
+ // either the linker will complain if it is used or the binary will end up
+ // segfaulting at runtime when run on 10.6. Rust by default supports OSX
+ // 10.7+, but there is a standard environment variable,
+ // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
+ // versions of OSX. For example compiling on 10.10 with
+ // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
+ // warnings about the usage of ELF TLS.
+ //
+ // Here we detect what version is being requested, defaulting to 10.7. ELF
+ // TLS is flagged as enabled if it looks to be supported.
+ let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
+ let version = deployment_target.as_ref().and_then(|s| {
+ let mut i = s.splitn(2, ".");
+ i.next().and_then(|a| i.next().map(|b| (a, b)))
+ }).and_then(|(a, b)| {
+ a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok()
+ }).unwrap_or((10, 7));
+
TargetOptions {
// OSX has -dead_strip, which doesn't rely on ffunction_sections
function_sections: false,
archive_format: "bsd".to_string(),
pre_link_args: Vec::new(),
exe_allocation_crate: super::maybe_jemalloc(),
+ has_elf_tls: version >= (10, 7),
.. Default::default()
}
}
dynamic_linking: false,
executables: true,
pre_link_args: pre_link_args(arch),
+ has_elf_tls: false,
.. super::apple_base::opts()
}
}
pub fn target() -> Target {
let mut base = super::android_base::opts();
base.features = "+v7".to_string();
+ base.has_elf_tls = false;
Target {
llvm_target: "arm-linux-androideabi".to_string(),
position_independent_executables: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::maybe_jemalloc(),
+ has_elf_tls: true,
.. Default::default()
}
}
/// Default crate for allocation symbols to link against
pub lib_allocation_crate: String,
pub exe_allocation_crate: String,
+
+ /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
+ /// this target.
+ pub has_elf_tls: bool,
}
impl Default for TargetOptions {
lib_allocation_crate: "alloc_system".to_string(),
exe_allocation_crate: "alloc_system".to_string(),
allow_asm: true,
+ has_elf_tls: false,
}
}
}
feature_gated_cfgs.sort();
feature_gated_cfgs.dedup();
for cfg in &feature_gated_cfgs {
- cfg.check_and_emit(sess.diagnostic(), &features);
+ cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
}
});
#![feature(borrow_state)]
#![feature(box_syntax)]
#![feature(cfg_target_vendor)]
+#![feature(cfg_target_thread_local)]
#![feature(char_internals)]
#![feature(clone_from_slice)]
#![feature(collections)]
//! the standard library This varies per-platform, but these libraries are
//! necessary for running libstd.
-// A few small shims in C that haven't been translated to Rust yet
-#[cfg(all(not(test), not(windows)))]
-#[link(name = "rust_builtin", kind = "static")]
-extern {}
-
// LLVM implements the `frem` instruction as a call to `fmod`, which lives in
// libm. Hence, we must explicitly link to it.
//
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io::{self, Error, ErrorKind, SeekFrom};
-use libc::{self, c_int, off_t, c_char, mode_t};
+use libc::{dirent, readdir_r};
+use libc::{self, c_int, off_t, mode_t};
use mem;
use path::{Path, PathBuf};
use ptr;
unsafe impl Sync for Dir {}
pub struct DirEntry {
- buf: Vec<u8>, // actually *mut libc::dirent
+ entry: dirent,
root: Arc<PathBuf>,
}
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
- extern {
- fn rust_dirent_t_size() -> libc::size_t;
- }
-
- let mut buf: Vec<u8> = Vec::with_capacity(unsafe {
- rust_dirent_t_size()
- });
- let ptr = buf.as_mut_ptr() as *mut libc::dirent;
-
- let mut entry_ptr = ptr::null_mut();
- loop {
- if unsafe { libc::readdir_r(self.dirp.0, ptr, &mut entry_ptr) != 0 } {
- return Some(Err(Error::last_os_error()))
- }
- if entry_ptr.is_null() {
- return None
- }
-
- let entry = DirEntry {
- buf: buf,
+ unsafe {
+ let mut ret = DirEntry {
+ entry: mem::zeroed(),
root: self.root.clone()
};
- if entry.name_bytes() == b"." || entry.name_bytes() == b".." {
- buf = entry.buf;
- } else {
- return Some(Ok(entry))
+ let mut entry_ptr = ptr::null_mut();
+ loop {
+ if readdir_r(self.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+ return Some(Err(Error::last_os_error()))
+ }
+ if entry_ptr.is_null() {
+ return None
+ }
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
}
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
- self.root.join(<OsStr as OsStrExt>::from_bytes(self.name_bytes()))
+ self.root.join(OsStr::from_bytes(self.name_bytes()))
}
pub fn file_name(&self) -> OsString {
}
pub fn file_type(&self) -> io::Result<FileType> {
- extern {
- fn rust_dir_get_mode(ptr: *mut libc::dirent) -> c_int;
- }
- unsafe {
- match rust_dir_get_mode(self.dirent()) {
- -1 => lstat(&self.path()).map(|m| m.file_type()),
- n => Ok(FileType { mode: n as mode_t }),
- }
+ match self.entry.d_type {
+ libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
+ libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }),
+ libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }),
+ libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }),
+ libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
+ libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
+ libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
+ _ => lstat(&self.path()).map(|m| m.file_type()),
}
}
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "linux"))]
pub fn ino(&self) -> raw::ino_t {
- extern {
- fn rust_dir_get_ino(ptr: *mut libc::dirent) -> raw::ino_t;
- }
- unsafe { rust_dir_get_ino(self.dirent()) }
+ self.entry.d_ino
+ }
+
+ #[cfg(target_os = "android")]
+ pub fn ino(&self) -> raw::ino_t {
+ self.entry.d_ino as raw::ino_t
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "dragonfly"))]
+ pub fn ino(&self) -> raw::ino_t {
+ self.entry.d_fileno
}
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "netbsd"))]
fn name_bytes(&self) -> &[u8] {
- extern {
- fn rust_list_dir_val(ptr: *mut libc::dirent) -> *const c_char;
+ unsafe {
+ ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
+ self.entry.d_namlen as usize)
}
+ }
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "openbsd"))]
+ fn name_bytes(&self) -> &[u8] {
unsafe {
- CStr::from_ptr(rust_list_dir_val(self.dirent())).to_bytes()
+ ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
+ self.entry.d_namelen as usize)
}
}
-
- fn dirent(&self) -> *mut libc::dirent {
- self.buf.as_ptr() as *mut _
+ #[cfg(any(target_os = "android",
+ target_os = "linux"))]
+ fn name_bytes(&self) -> &[u8] {
+ unsafe {
+ CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
+ }
}
}
/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
extern {
- #[cfg_attr(any(target_os = "linux", target_os = "android"), link_name = "__errno_location")]
- #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd",
+ #[cfg_attr(any(target_os = "linux"), link_name = "__errno_location")]
+ #[cfg_attr(any(target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "android",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "dragonfly", link_name = "__dfly_error")]
- #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "freebsd"),
+ #[cfg_attr(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd"),
link_name = "__error")]
fn errno_location() -> *const c_int;
}
libc::KERN_PROC_PATHNAME as c_int,
-1 as c_int];
let mut sz: libc::size_t = 0;
- let err = libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
- ptr::null_mut(), &mut sz, ptr::null_mut(),
- 0 as libc::size_t);
- if err != 0 { return Err(io::Error::last_os_error()); }
- if sz == 0 { return Err(io::Error::last_os_error()); }
+ try!(cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+ ptr::null_mut(), &mut sz, ptr::null_mut(),
+ 0 as libc::size_t)));
+ if sz == 0 {
+ return Err(io::Error::last_os_error())
+ }
let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
- let err = libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
- v.as_mut_ptr() as *mut libc::c_void, &mut sz,
- ptr::null_mut(), 0 as libc::size_t);
- if err != 0 { return Err(io::Error::last_os_error()); }
- if sz == 0 { return Err(io::Error::last_os_error()); }
+ try!(cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+ v.as_mut_ptr() as *mut libc::c_void, &mut sz,
+ ptr::null_mut(), 0 as libc::size_t)));
+ if sz == 0 {
+ return Err(io::Error::last_os_error());
+ }
v.set_len(sz as usize - 1); // chop off trailing NUL
Ok(PathBuf::from(OsString::from_vec(v)))
}
#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub fn current_exe() -> io::Result<PathBuf> {
- use sync::StaticMutex;
- static LOCK: StaticMutex = StaticMutex::new();
-
- extern {
- fn rust_current_exe() -> *const c_char;
- }
-
- let _guard = LOCK.lock();
-
unsafe {
- let v = rust_current_exe();
- if v.is_null() {
- Err(io::Error::last_os_error())
+ let mut mib = [libc::CTL_KERN,
+ libc::KERN_PROC_ARGS,
+ libc::getpid(),
+ libc::KERN_PROC_ARGV];
+ let mib = mib.as_mut_ptr();
+ let mut argv_len = 0;
+ try!(cvt(libc::sysctl(mib, 4, 0 as *mut _, &mut argv_len,
+ 0 as *mut _, 0)));
+ let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize);
+ try!(cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _,
+ &mut argv_len, 0 as *mut _, 0)));
+ argv.set_len(argv_len as usize);
+ if argv[0].is_null() {
+ return Err(io::Error::new(io::ErrorKind::Other,
+ "no current exe available"))
+ }
+ let argv0 = CStr::from_ptr(argv[0]).to_bytes();
+ if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') {
+ ::fs::canonicalize(OsStr::from_bytes(argv0))
} else {
- let vec = CStr::from_ptr(v).to_bytes().to_vec();
- Ok(PathBuf::from(OsString::from_vec(vec)))
+ Ok(PathBuf::from(OsStr::from_bytes(argv0)))
}
}
}
use cell::UnsafeCell;
use mem;
-// Sure wish we had macro hygiene, no?
-#[doc(hidden)]
-pub use self::imp::Key as __KeyInner;
-
/// A thread local storage key which owns its contents.
///
/// This key uses the fastest possible implementation available to it for the
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct LocalKey<T:'static> {
- // The key itself may be tagged with #[thread_local], and this `Key` is
- // stored as a `static`, and it's not valid for a static to reference the
- // address of another thread_local static. For this reason we kinda wonkily
- // work around this by generating a shim function which will give us the
- // address of the inner TLS key at runtime.
+pub struct LocalKey<T: 'static> {
+ // This outer `LocalKey<T>` type is what's going to be stored in statics,
+ // but actual data inside will sometimes be tagged with #[thread_local].
+ // It's not valid for a true static to reference a #[thread_local] static,
+ // so we get around that by exposing an accessor through a layer of function
+ // indirection (this thunk).
+ //
+ // Note that the thunk is itself unsafe because the returned lifetime of the
+ // slot where data lives, `'static`, is not actually valid. The lifetime
+ // here is actually `'thread`!
//
- // This is trivially devirtualizable by LLVM because we never store anything
- // to this field and rustc can declare the `static` as constant as well.
- inner: fn() -> &'static __KeyInner<T>,
+ // Although this is an extra layer of indirection, it should in theory be
+ // trivially devirtualizable by LLVM because the value of `inner` never
+ // changes and the constant should be readonly within a crate. This mainly
+ // only runs into problems when TLS statics are exported across crates.
+ inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
// initialization routine to invoke to create a value
init: fn() -> T,
}
-// Macro pain #4586:
-//
-// When cross compiling, rustc will load plugins and macros from the *host*
-// platform before search for macros from the target platform. This is primarily
-// done to detect, for example, plugins. Ideally the macro below would be
-// defined once per module below, but unfortunately this means we have the
-// following situation:
-//
-// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
-// will inject #[thread_local] statics.
-// 2. We then try to compile a program for arm-linux-androideabi
-// 3. The compiler has a host of linux and a target of android, so it loads
-// macros from the *linux* libstd.
-// 4. The macro generates a #[thread_local] field, but the android libstd does
-// not use #[thread_local]
-// 5. Compile error about structs with wrong fields.
-//
-// To get around this, we're forced to inject the #[cfg] logic into the macro
-// itself. Woohoo.
-
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
///
/// See [LocalKey documentation](thread/struct.LocalKey.html) for more
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
-#[cfg(not(no_elf_tls))]
-macro_rules! thread_local {
- (static $name:ident: $t:ty = $init:expr) => (
- static $name: $crate::thread::LocalKey<$t> =
- __thread_local_inner!($t, $init,
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]);
- );
- (pub static $name:ident: $t:ty = $init:expr) => (
- pub static $name: $crate::thread::LocalKey<$t> =
- __thread_local_inner!($t, $init,
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]);
- );
-}
-
-#[macro_export]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
-#[cfg(no_elf_tls)]
macro_rules! thread_local {
(static $name:ident: $t:ty = $init:expr) => (
static $name: $crate::thread::LocalKey<$t> =
- __thread_local_inner!($t, $init, #[]);
+ __thread_local_inner!($t, $init);
);
(pub static $name:ident: $t:ty = $init:expr) => (
pub static $name: $crate::thread::LocalKey<$t> =
- __thread_local_inner!($t, $init, #[]);
+ __thread_local_inner!($t, $init);
);
}
#[macro_export]
#[allow_internal_unstable]
macro_rules! __thread_local_inner {
- ($t:ty, $init:expr, #[$($attr:meta),*]) => {{
- $(#[$attr])*
- static __KEY: $crate::thread::__LocalKeyInner<$t> =
- $crate::thread::__LocalKeyInner::new();
+ ($t:ty, $init:expr) => {{
fn __init() -> $t { $init }
- fn __getit() -> &'static $crate::thread::__LocalKeyInner<$t> { &__KEY }
+
+ unsafe fn __getit() -> $crate::option::Option<
+ &'static $crate::cell::UnsafeCell<
+ $crate::option::Option<$t>>>
+ {
+ #[thread_local]
+ #[cfg(target_thread_local)]
+ static __KEY: $crate::thread::__ElfLocalKeyInner<$t> =
+ $crate::thread::__ElfLocalKeyInner::new();
+
+ #[cfg(not(target_thread_local))]
+ static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
+ $crate::thread::__OsLocalKeyInner::new();
+
+ __KEY.get()
+ }
+
$crate::thread::LocalKey::new(__getit, __init)
}}
}
#[unstable(feature = "thread_local_internals",
reason = "recently added to create a key",
issue = "0")]
- pub const fn new(inner: fn() -> &'static __KeyInner<T>,
+ pub const fn new(inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
init: fn() -> T) -> LocalKey<T> {
LocalKey {
inner: inner,
- init: init
+ init: init,
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with<F, R>(&'static self, f: F) -> R
where F: FnOnce(&T) -> R {
- let slot = (self.inner)();
unsafe {
- let slot = slot.get().expect("cannot access a TLS value during or \
- after it is destroyed");
+ let slot = (self.inner)();
+ let slot = slot.expect("cannot access a TLS value during or \
+ after it is destroyed");
f(match *slot.get() {
Some(ref inner) => inner,
None => self.init(slot),
issue = "27716")]
pub fn state(&'static self) -> LocalKeyState {
unsafe {
- match (self.inner)().get() {
+ match (self.inner)() {
Some(cell) => {
match *cell.get() {
Some(..) => LocalKeyState::Valid,
}
}
-#[cfg(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64"),
- not(no_elf_tls)))]
+#[cfg(target_thread_local)]
#[doc(hidden)]
-mod imp {
+pub mod elf {
use cell::{Cell, UnsafeCell};
use intrinsics;
use ptr;
}
}
-#[cfg(any(not(any(target_os = "macos", target_os = "linux")),
- target_arch = "aarch64",
- no_elf_tls))]
#[doc(hidden)]
-mod imp {
+pub mod os {
use prelude::v1::*;
use cell::{Cell, UnsafeCell};
pub use self::scoped_tls::ScopedKey;
#[unstable(feature = "libstd_thread_internals", issue = "0")]
-#[doc(hidden)] pub use self::local::__KeyInner as __LocalKeyInner;
+#[cfg(target_thread_local)]
+#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner;
+#[unstable(feature = "libstd_thread_internals", issue = "0")]
+#[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner;
#[unstable(feature = "libstd_thread_internals", issue = "0")]
#[doc(hidden)] pub use self::scoped_tls::__KeyInner as __ScopedKeyInner;
// allow using type ascription in expressions
("type_ascription", "1.6.0", Some(23416), Active),
+
+ // Allows cfg(target_thread_local)
+ ("cfg_target_thread_local", "1.7.0", Some(29594), Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
// (name in cfg, feature, function to check if the feature is enabled)
("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
+ ("target_thread_local", "cfg_target_thread_local",
+ cfg_fn!(|x| x.cfg_target_thread_local)),
];
#[derive(Debug, Eq, PartialEq)]
}
impl GatedCfgAttr {
- pub fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
+ pub fn check_and_emit(&self,
+ diagnostic: &Handler,
+ features: &Features,
+ codemap: &CodeMap) {
match *self {
GatedCfgAttr::GatedCfg(ref cfg) => {
- cfg.check_and_emit(diagnostic, features);
+ cfg.check_and_emit(diagnostic, features, codemap);
}
GatedCfgAttr::GatedAttr(span) => {
if !features.stmt_expr_attributes {
}
})
}
- fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
+ fn check_and_emit(&self,
+ diagnostic: &Handler,
+ features: &Features,
+ codemap: &CodeMap) {
let (cfg, feature, has_feature) = GATED_CFGS[self.index];
- if !has_feature(features) {
+ if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
}
pub type_macros: bool,
pub cfg_target_feature: bool,
pub cfg_target_vendor: bool,
+ pub cfg_target_thread_local: bool,
pub augmented_assignments: bool,
pub braced_empty_structs: bool,
pub staged_api: bool,
type_macros: false,
cfg_target_feature: false,
cfg_target_vendor: false,
+ cfg_target_thread_local: false,
augmented_assignments: false,
braced_empty_structs: false,
staged_api: false,
type_macros: cx.has_feature("type_macros"),
cfg_target_feature: cx.has_feature("cfg_target_feature"),
cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
+ cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
augmented_assignments: cx.has_feature("augmented_assignments"),
braced_empty_structs: cx.has_feature("braced_empty_structs"),
staged_api: cx.has_feature("staged_api"),
}
}
- #[cfg(unix)]
+ #[cfg(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "android"))]
fn num_cpus() -> usize {
- extern { fn rust_get_num_cpus() -> libc::uintptr_t; }
- unsafe { rust_get_num_cpus() as usize }
+ unsafe {
+ libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize
+ }
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "openbsd",
+ target_os = "netbsd"))]
+ fn num_cpus() -> usize {
+ let mut cpus: libc::c_uint = 0;
+ let mut CPUS_SIZE = std::mem::size_of_val(&cpus);
+ let mut mib = [libc::CTL_HW, libc::HW_AVAILCPU, 0, 0];
+
+ unsafe {
+ libc::sysctl(mib.as_mut_ptr(), 2,
+ &mut cpus as *mut _ as *mut _,
+ &mut CPUS_SIZE as *mut _ as *mut _,
+ 0 as *mut _, 0);
+ }
+ if cpus < 1 {
+ mib[1] = HW_NCPU;
+ unsafe {
+ libc::sysctl(mib.as_mut_ptr(), 2,
+ &mut cpus as *mut _ as *mut _,
+ &mut CPUS_SIZE as *mut _ as *mut _,
+ 0 as *mut _, 0);
+ }
+ if cpus < 1 {
+ cpus = 1;
+ }
+ }
+ cpus as usize
}
}
+++ /dev/null
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifdef __ANDROID__
-
-#include "rust_android_dummy.h"
-#include <math.h>
-#include <errno.h>
-
-int backtrace(void **array, int size) { return 0; }
-
-char **backtrace_symbols(void *const *array, int size) { return 0; }
-
-void backtrace_symbols_fd (void *const *array, int size, int fd) {}
-
-volatile int* __errno_location() {
- return &errno;
-}
-
-float log2f(float f)
-{
- return logf( f ) / logf( 2 );
-}
-
-double log2( double n )
-{
- return log( n ) / log( 2 );
-}
-
-double exp10( double x )
-{
- return pow( 10, x );
-}
-
-void telldir()
-{
-}
-
-void seekdir()
-{
-}
-
-void mkfifo()
-{
-}
-
-void abs()
-{
-}
-
-void labs()
-{
-}
-
-void rand()
-{
-}
-
-void srand()
-{
-}
-
-void atof()
-{
-}
-
-int glob(const char *pattern,
- int flags,
- int (*errfunc) (const char *epath, int eerrno),
- glob_t *pglob)
-{
- return 0;
-}
-
-void globfree(glob_t *pglob)
-{
-}
-
-int pthread_atfork(void (*prefork)(void),
- void (*postfork_parent)(void),
- void (*postfork_child)(void))
-{
- return 0;
-}
-
-int mlockall(int flags)
-{
- return 0;
-}
-
-int munlockall(void)
-{
- return 0;
-}
-
-int shm_open(const char *name, int oflag, mode_t mode)
-{
- return 0;
-}
-
-int shm_unlink(const char *name)
-{
- return 0;
-}
-
-int posix_madvise(void *addr, size_t len, int advice)
-{
- return 0;
-}
-
-#endif
+++ /dev/null
-// Copyright 2012-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.
-
-#if !defined(_WIN32)
-
-#include <stdint.h>
-#include <time.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-
-
-#include <dirent.h>
-#include <pthread.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#include <mach/mach_time.h>
-
-#if !(TARGET_OS_IPHONE)
-#include <crt_externs.h>
-#endif
-#endif
-
-char*
-rust_list_dir_val(struct dirent* entry_ptr) {
- return entry_ptr->d_name;
-}
-
-// Android's struct dirent does have d_type from the very beginning
-// (android-3). _DIRENT_HAVE_D_TYPE is not defined all the way to android-21
-// though...
-#if defined(__ANDROID__)
-# define _DIRENT_HAVE_D_TYPE
-#endif
-
-int
-rust_dir_get_mode(struct dirent* entry_ptr) {
-#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
- switch (entry_ptr->d_type) {
- case DT_BLK: return S_IFBLK;
- case DT_CHR: return S_IFCHR;
- case DT_FIFO: return S_IFIFO;
- case DT_LNK: return S_IFLNK;
- case DT_REG: return S_IFREG;
- case DT_SOCK: return S_IFSOCK;
- case DT_DIR: return S_IFDIR;
- }
-#endif
- return -1;
-}
-
-ino_t
-rust_dir_get_ino(struct dirent* entry_ptr) {
- return entry_ptr->d_ino;
-}
-
-DIR*
-rust_opendir(char *dirname) {
- return opendir(dirname);
-}
-
-int
-rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
- return readdir_r(dirp, entry, result);
-}
-
-size_t
-rust_dirent_t_size() {
- return sizeof(struct dirent);
-}
-
-#if defined(__BSD__)
-static int
-get_num_cpus() {
- /* swiped from http://stackoverflow.com/questions/150355/
- programmatically-find-the-number-of-cores-on-a-machine */
-
- unsigned int numCPU;
- int mib[4];
- size_t len = sizeof(numCPU);
-
- /* set the mib for hw.ncpu */
- mib[0] = CTL_HW;
- mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
-
- /* get the number of CPUs from the system */
- sysctl(mib, 2, &numCPU, &len, NULL, 0);
-
- if( numCPU < 1 ) {
- mib[1] = HW_NCPU;
- sysctl( mib, 2, &numCPU, &len, NULL, 0 );
-
- if( numCPU < 1 ) {
- numCPU = 1;
- }
- }
- return numCPU;
-}
-#elif defined(__GNUC__)
-static int
-get_num_cpus() {
- return sysconf(_SC_NPROCESSORS_ONLN);
-}
-#endif
-
-uintptr_t
-rust_get_num_cpus() {
- return get_num_cpus();
-}
-
-#if defined(__DragonFly__)
-#include <errno.h>
-// In DragonFly __error() is an inline function and as such
-// no symbol exists for it.
-int *__dfly_error(void) { return __error(); }
-#endif
-
-#if defined(__Bitrig__)
-#include <stdio.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <limits.h>
-
-int rust_get_path(void *p, size_t* sz)
-{
- int mib[4];
- char *eq = NULL;
- char *key = NULL;
- char *val = NULL;
- char **menv = NULL;
- size_t maxlen, len;
- int nenv = 0;
- int i;
-
- if ((p == NULL) && (sz == NULL))
- return -1;
-
- /* get the argv array */
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC_ARGS;
- mib[2] = getpid();
- mib[3] = KERN_PROC_ENV;
-
- /* get the number of bytes needed to get the env */
- maxlen = 0;
- if (sysctl(mib, 4, NULL, &maxlen, NULL, 0) == -1)
- return -1;
-
- /* allocate the buffer */
- if ((menv = calloc(maxlen, sizeof(char))) == NULL)
- return -1;
-
- /* get the env array */
- if (sysctl(mib, 4, menv, &maxlen, NULL, 0) == -1)
- {
- free(menv);
- return -1;
- }
-
- mib[3] = KERN_PROC_NENV;
- len = sizeof(int);
- /* get the length of env array */
- if (sysctl(mib, 4, &nenv, &len, NULL, 0) == -1)
- {
- free(menv);
- return -1;
- }
-
- /* find _ key and resolve the value */
- for (i = 0; i < nenv; i++)
- {
- if ((eq = strstr(menv[i], "=")) == NULL)
- continue;
-
- key = menv[i];
- val = eq + 1;
- *eq = '\0';
-
- if (strncmp(key, "PATH", maxlen) != 0)
- continue;
-
- if (p == NULL)
- {
- /* return the length of the value + NUL */
- *sz = strnlen(val, maxlen) + 1;
- free(menv);
- return 0;
- }
- else
- {
- /* copy *sz bytes to the output buffer */
- memcpy(p, val, *sz);
- free(menv);
- return 0;
- }
- }
-
- free(menv);
- return -1;
-}
-
-int rust_get_path_array(void * p, size_t * sz)
-{
- char *path, *str;
- char **buf;
- int i, num;
- size_t len;
-
- if ((p == NULL) && (sz == NULL))
- return -1;
-
- /* get the length of the PATH value */
- if (rust_get_path(NULL, &len) == -1)
- return -1;
-
- if (len == 0)
- return -1;
-
- /* allocate the buffer */
- if ((path = calloc(len, sizeof(char))) == NULL)
- return -1;
-
- /* get the PATH value */
- if (rust_get_path(path, &len) == -1)
- {
- free(path);
- return -1;
- }
-
- /* count the number of parts in the PATH */
- num = 1;
- for(str = path; *str != '\0'; str++)
- {
- if (*str == ':')
- num++;
- }
-
- /* calculate the size of the buffer for the 2D array */
- len = (num * sizeof(char*) + 1) + strlen(path) + 1;
-
- if (p == NULL)
- {
- free(path);
- *sz = len;
- return 0;
- }
-
- /* make sure we have enough buffer space */
- if (*sz < len)
- {
- free(path);
- return -1;
- }
-
- /* zero out the buffer */
- buf = (char**)p;
- memset(buf, 0, *sz);
-
- /* copy the data into the right place */
- str = p + ((num+1) * sizeof(char*));
- memcpy(str, path, strlen(path));
-
- /* parse the path into it's parts */
- for (i = 0; i < num && (buf[i] = strsep(&str, ":")) != NULL; i++) {;}
- buf[num] = NULL;
-
- free(path);
- return 0;
-}
-
-int rust_get_argv_zero(void* p, size_t* sz)
-{
- int mib[4];
- char **argv = NULL;
- size_t len;
-
- if ((p == NULL) && (sz == NULL))
- return -1;
-
- /* get the argv array */
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC_ARGS;
- mib[2] = getpid();
- mib[3] = KERN_PROC_ARGV;
-
- /* request KERN_PROC_ARGV size */
- len = 0;
- if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1)
- return -1;
-
- /* allocate buffer to receive the values */
- if ((argv = malloc(len)) == NULL)
- return -1;
-
- /* get the argv array */
- if (sysctl(mib, 4, argv, &len, NULL, 0) == -1)
- {
- free(argv);
- return -1;
- }
-
- /* get length of argv[0] */
- len = strnlen(argv[0], len) + 1;
-
- if (p == NULL)
- {
- *sz = len;
- free(argv);
- return 0;
- }
-
- if (*sz < len)
- {
- free(argv);
- return -1;
- }
-
- memcpy(p, argv[0], len);
- free(argv);
- return 0;
-}
-
-const char * rust_current_exe()
-{
- static char *self = NULL;
- char *argv0;
- char **paths;
- size_t sz;
- int i;
- /* If `PATH_MAX` is defined on the platform, `realpath` will truncate the
- * resolved path up to `PATH_MAX`. While this can make the resolution fail if
- * the executable is placed in a deep path, the usage of a buffer whose
- * length depends on `PATH_MAX` is still memory safe. */
- char buf[2*PATH_MAX], exe[PATH_MAX];
-
- if (self != NULL)
- return self;
-
- if (rust_get_argv_zero(NULL, &sz) == -1)
- return NULL;
- if ((argv0 = calloc(sz, sizeof(char))) == NULL)
- return NULL;
- if (rust_get_argv_zero(argv0, &sz) == -1)
- {
- free(argv0);
- return NULL;
- }
-
- /* if argv0 is a relative or absolute path, resolve it with realpath */
- if ((*argv0 == '.') || (*argv0 == '/') || (strstr(argv0, "/") != NULL))
- {
- self = realpath(argv0, NULL);
- free(argv0);
- return self;
- }
-
- /* get the path array */
- if (rust_get_path_array(NULL, &sz) == -1)
- {
- free(argv0);
- return NULL;
- }
- if ((paths = calloc(sz, sizeof(char))) == NULL)
- {
- free(argv0);
- return NULL;
- }
- if (rust_get_path_array(paths, &sz) == -1)
- {
- free(argv0);
- free(paths);
- return NULL;
- }
-
- for(i = 0; paths[i] != NULL; i++)
- {
- snprintf(buf, 2*PATH_MAX, "%s/%s", paths[i], argv0);
- if (realpath(buf, exe) == NULL)
- continue;
-
- if (access(exe, F_OK | X_OK) == -1)
- continue;
-
- self = strdup(exe);
- free(argv0);
- free(paths);
- return self;
- }
-
- free(argv0);
- free(paths);
- return NULL;
-}
-
-#elif defined(__OpenBSD__)
-
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <limits.h>
-
-const char * rust_current_exe() {
- static char *self = NULL;
-
- if (self == NULL) {
- int mib[4];
- char **argv = NULL;
- size_t argv_len;
-
- /* initialize mib */
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC_ARGS;
- mib[2] = getpid();
- mib[3] = KERN_PROC_ARGV;
-
- /* request KERN_PROC_ARGV size */
- argv_len = 0;
- if (sysctl(mib, 4, NULL, &argv_len, NULL, 0) == -1)
- return (NULL);
-
- /* allocate size */
- if ((argv = malloc(argv_len)) == NULL)
- return (NULL);
-
- /* request KERN_PROC_ARGV */
- if (sysctl(mib, 4, argv, &argv_len, NULL, 0) == -1) {
- free(argv);
- return (NULL);
- }
-
- /* get realpath if possible */
- if ((argv[0] != NULL) && ((*argv[0] == '.') || (*argv[0] == '/')
- || (strstr(argv[0], "/") != NULL)))
-
- self = realpath(argv[0], NULL);
- else
- self = NULL;
-
- /* cleanup */
- free(argv);
- }
-
- return (self);
-}
-
-#endif
-
-#endif // !defined(_WIN32)
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//