GDB and LLDB pretty printers have some common functionality and also access some common information, such as the layout of standard library types. So far, this information has been duplicated in the two pretty printing python modules. This PR introduces a common module used by both debuggers.
This PR also implements proper rendering of `String` and `&str` values in LLDB.
# This is used by the automation to produce single-target nightlies
opt dist-host-only 0 "only install bins for the host architecture"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
-opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway"
+opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
# Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code"
opt_nosave manage-submodules 1 "let the build manage the git submodules"
opt_nosave clang 0 "prefer clang to gcc for building the runtime"
opt_nosave jemalloc 1 "build liballoc with jemalloc"
+opt elf-tls 1 "elf thread local storage on platforms where supported"
valopt_nosave prefix "/usr/local" "set installation prefix"
valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \
$(S)src/librustc_llvm/lib.rs
$(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA)
+
+# All windows nightiles are currently a GNU triple, so this MSVC triple is not
+# bootstrapping from itself. This is relevant during stage0, and other parts of
+# the build system take this into account.
+BOOTSTRAP_FROM_x86_64-pc-windows-msvc := x86_64-pc-windows-gnu
endef
$(foreach crate,$(TOOLS),$(eval $(call RUST_TOOL,$(crate))))
+
+ifdef CFG_DISABLE_ELF_TLS
+RUSTFLAGS_std := --cfg no_elf_tls
+endif
endif
endif
-CFG_BUILD_DATE = $(shell date +%F)
-CFG_VERSION += (built $(CFG_BUILD_DATE))
-
# Windows exe's need numeric versions - don't use anything but
# numbers and dots here
CFG_VERSION_WIN = $(CFG_RELEASE_NUM)
ifdef CFG_ENABLE_DEBUG_ASSERTIONS
$(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS))
- CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
-else
- CFG_RUSTC_FLAGS += --cfg ndebug
+ CFG_RUSTC_FLAGS += -C debug-assertions=on
endif
ifdef CFG_ENABLE_DEBUGINFO
ifdef CFG_VER_HASH
export CFG_VER_HASH
endif
-export CFG_BUILD_DATE
export CFG_VERSION
export CFG_VERSION_WIN
export CFG_RELEASE
$(foreach stage,$(STAGES), \
$(foreach tool,$(TOOLS), \
$(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))
+
+# We have some triples which are bootstrapped from other triples, and this means
+# that we need to fixup some of the native tools that a triple depends on.
+#
+# For example, MSVC requires the llvm-ar.exe executable to manage archives, but
+# it bootstraps from the GNU Windows triple. This means that the compiler will
+# add this directory to PATH when executing new processes:
+#
+# $SYSROOT/rustlib/x86_64-pc-windows-gnu/bin
+#
+# Unfortunately, however, the GNU triple is not known about in stage0, so the
+# tools are actually located in:
+#
+# $SYSROOT/rustlib/x86_64-pc-windows-msvc/bin
+#
+# To remedy this problem, the rules below copy all native tool dependencies into
+# the bootstrap triple's location in stage 0 so the bootstrap compiler can find
+# the right sets of tools. Later stages (1+) will have the right host triple for
+# the compiler, so there's no need to worry there.
+#
+# $(1) - stage
+# $(2) - triple that's being used as host/target
+# $(3) - triple snapshot is built for
+# $(4) - crate
+# $(5) - tool
+define MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR
+ifneq (,$(3))
+$$(TLIB$(1)_T_$(2)_H_$(2))/stamp.$(4): $$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5)
+
+$$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5): $$(TBIN$(1)_T_$(2)_H_$(2))/$(5)
+ mkdir -p $$(@D)
+ cp $$< $$@
+endif
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(foreach crate,$(CRATES), \
+ $(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
+ $(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# As above but don't bother running tidy.
-check-notidy: cleantmptestlogs cleantestlibs all check-stage2
+check-notidy: check-sanitycheck cleantmptestlogs cleantestlibs all check-stage2
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# A slightly smaller set of tests for smoke testing.
-check-lite: cleantestlibs cleantmptestlogs \
+check-lite: check-sanitycheck cleantestlibs cleantmptestlogs \
$(foreach crate,$(TEST_TARGET_CRATES),check-stage2-$(crate)) \
check-stage2-rpass check-stage2-rpass-valgrind \
check-stage2-rfail check-stage2-cfail check-stage2-pfail check-stage2-rmake
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Only check the 'reference' tests: rpass/cfail/rfail/rmake.
-check-ref: cleantestlibs cleantmptestlogs check-stage2-rpass check-stage2-rpass-valgrind \
- check-stage2-rfail check-stage2-cfail check-stage2-pfail check-stage2-rmake
+check-ref: check-sanitycheck cleantestlibs cleantmptestlogs check-stage2-rpass \
+ check-stage2-rpass-valgrind check-stage2-rfail check-stage2-cfail check-stage2-pfail \
+ check-stage2-rmake
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Only check the docs.
-check-docs: cleantestlibs cleantmptestlogs check-stage2-docs
+check-docs: check-sanitycheck cleantestlibs cleantmptestlogs check-stage2-docs
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Some less critical tests that are not prone to breakage.
If you encounter an error while compiling your code you may be able to look it
up in the [Rust Compiler Error Index](error-index.html).
+
+# Community Translations
+
+Several projects have been started to translate the documentation into other
+languages:
+
+- [Russian](https://github.com/kgv/rust_book_ru)
+- [Korean](https://github.com/rust-kr/doc.rust-kr.org)
+- [Chinese](https://github.com/KaiserY/rust-book-chinese)
+- [Spanish](https://github.com/goyox86/elpr)
+
```rust
fn main() {
- println!("Hello, world!")
+ println!("Hello, world!");
}
```
Cargo uses the dependencies section to know what dependencies on external
crates you have, and what versions you require. In this case, we’ve used version `0.3.0`.
Cargo understands [Semantic Versioning][semver], which is a standard for writing version
-numbers. If we wanted to use the latest version we could use `*` or we could use a range
+numbers. If we wanted to use the latest version we could use `*` or we could use a range
of versions. [Cargo’s documentation][cargodoc] contains more details.
[semver]: http://semver.org
The first step to using Rust is to install it! There are a number of ways to
install Rust, but the easiest is to use the `rustup` script. If you're on Linux
-or a Mac, all you need to do is this (note that you don't need to type in the
-`$`s, they just indicate the start of each command):
+or a Mac, all you need to do is this:
+
+> Note: you don't need to type in the `$`s, they just indicate the start of
+> each command. You’ll see many tutorials and examples around the web that
+> follow this convention: `$` for commands run as your regular user, and
+> `#` for commands you should be running as an administrator.
```bash
$ curl -sf -L https://static.rust-lang.org/rustup.sh | sh
`.next()` method on repeatedly, and it gives us a sequence of things.
Because you need to call the method, this means that iterators
can be *lazy* and not generate all of the values upfront. This code,
-for example, does not actually generate the numbers `1-100`, instead
+for example, does not actually generate the numbers `1-99`, instead
creating a value that merely represents the sequence:
```rust
a few times, and then consume the result. Check it out:
```rust
-(1..1000)
+(1..)
.filter(|&x| x % 2 == 0)
.filter(|&x| x % 3 == 0)
.take(5)
> * exactly one mutable reference (`&mut T`)
[ownership]: ownership.html
-[borrowing]: borrowing.html#The-Rules
+[borrowing]: references-and-borrowing.html#borrowing
So, that’s the real definition of ‘immutability’: is this safe to have two
pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside
# FFI
Raw pointers are useful for FFI: Rust’s `*const T` and `*mut T` are similar to
-C’s `const T*` and `T*`, respectfully. For more about this use, consult the
+C’s `const T*` and `T*`, respectively. For more about this use, consult the
[FFI chapter][ffi].
[ffi]: ffi.html
# except according to those terms.
import os
+import subprocess
import sys
import functools
STATUS = 0
-
def error_unless_permitted(env_var, message):
global STATUS
if not os.getenv(env_var):
sys.stderr.write(message)
STATUS = 1
-
def only_on(platforms):
def decorator(func):
@functools.wraps(func)
return inner
return decorator
-
-@only_on(('linux', 'darwin', 'freebsd', 'openbsd'))
+@only_on(['linux', 'darwin', 'freebsd', 'openbsd'])
def check_rlimit_core():
import resource
soft, hard = resource.getrlimit(resource.RLIMIT_CORE)
set ALLOW_NONZERO_RLIMIT_CORE to ignore this warning
""" % (soft))
+@only_on(['win32'])
+def check_console_code_page():
+ if '65001' not in subprocess.check_output(['cmd', '/c', 'chcp']):
+ sys.stderr.write('Warning: the console output code page is not UTF-8, \
+some tests may fail. Use `cmd /c "chcp 65001"` to setup UTF-8 code page.\n')
def main():
+ check_console_code_page()
check_rlimit_core()
if __name__ == '__main__':
///
/// Returns `None` if the `Arc<T>` is not unique.
///
+/// This function is marked **unsafe** because it is racy if weak pointers
+/// are active.
+///
/// # Examples
///
/// ```
/// # fn main() {
/// use alloc::arc::{Arc, get_mut};
///
+/// # unsafe {
/// let mut x = Arc::new(3);
/// *get_mut(&mut x).unwrap() = 4;
/// assert_eq!(*x, 4);
/// let _y = x.clone();
/// assert!(get_mut(&mut x).is_none());
/// # }
+/// # }
/// ```
#[inline]
#[unstable(feature = "alloc")]
-pub fn get_mut<T: ?Sized>(this: &mut Arc<T>) -> Option<&mut T> {
+pub unsafe fn get_mut<T: ?Sized>(this: &mut Arc<T>) -> Option<&mut T> {
+ // FIXME(#24880) potential race with upgraded weak pointers here
if strong_count(this) == 1 && weak_count(this) == 0 {
// This unsafety is ok because we're guaranteed that the pointer
// returned is the *only* pointer that will ever be returned to T. Our
// reference count is guaranteed to be 1 at this point, and we required
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
- let inner = unsafe { &mut **this._ptr };
+ let inner = &mut **this._ptr;
Some(&mut inner.data)
} else {
None
/// This is also referred to as a copy-on-write operation because the inner
/// data is cloned if the reference count is greater than one.
///
+ /// This method is marked **unsafe** because it is racy if weak pointers
+ /// are active.
+ ///
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
+ /// # unsafe {
/// let mut five = Arc::new(5);
///
/// let mut_five = five.make_unique();
+ /// # }
/// ```
#[inline]
#[unstable(feature = "alloc")]
- pub fn make_unique(&mut self) -> &mut T {
+ pub unsafe fn make_unique(&mut self) -> &mut T {
+ // FIXME(#24880) potential race with upgraded weak pointers here
+ //
// Note that we hold a strong reference, which also counts as a weak
// reference, so we only clone if there is an additional reference of
// either kind.
}
// As with `get_mut()`, the unsafety is ok because our reference was
// either unique to begin with, or became one upon cloning the contents.
- let inner = unsafe { &mut **self._ptr };
+ let inner = &mut **self._ptr;
&mut inner.data
}
}
#[test]
fn test_arc_get_mut() {
- let mut x = Arc::new(3);
- *get_mut(&mut x).unwrap() = 4;
- assert_eq!(*x, 4);
- let y = x.clone();
- assert!(get_mut(&mut x).is_none());
- drop(y);
- assert!(get_mut(&mut x).is_some());
- let _w = x.downgrade();
- assert!(get_mut(&mut x).is_none());
+ unsafe {
+ let mut x = Arc::new(3);
+ *get_mut(&mut x).unwrap() = 4;
+ assert_eq!(*x, 4);
+ let y = x.clone();
+ assert!(get_mut(&mut x).is_none());
+ drop(y);
+ assert!(get_mut(&mut x).is_some());
+ let _w = x.downgrade();
+ assert!(get_mut(&mut x).is_none());
+ }
}
#[test]
fn test_cowarc_clone_make_unique() {
- let mut cow0 = Arc::new(75);
- let mut cow1 = cow0.clone();
- let mut cow2 = cow1.clone();
-
- assert!(75 == *cow0.make_unique());
- assert!(75 == *cow1.make_unique());
- assert!(75 == *cow2.make_unique());
-
- *cow0.make_unique() += 1;
- *cow1.make_unique() += 2;
- *cow2.make_unique() += 3;
-
- assert!(76 == *cow0);
- assert!(77 == *cow1);
- assert!(78 == *cow2);
-
- // none should point to the same backing memory
- assert!(*cow0 != *cow1);
- assert!(*cow0 != *cow2);
- assert!(*cow1 != *cow2);
+ unsafe {
+ let mut cow0 = Arc::new(75);
+ let mut cow1 = cow0.clone();
+ let mut cow2 = cow1.clone();
+
+ assert!(75 == *cow0.make_unique());
+ assert!(75 == *cow1.make_unique());
+ assert!(75 == *cow2.make_unique());
+
+ *cow0.make_unique() += 1;
+ *cow1.make_unique() += 2;
+ *cow2.make_unique() += 3;
+
+ assert!(76 == *cow0);
+ assert!(77 == *cow1);
+ assert!(78 == *cow2);
+
+ // none should point to the same backing memory
+ assert!(*cow0 != *cow1);
+ assert!(*cow0 != *cow2);
+ assert!(*cow1 != *cow2);
+ }
}
#[test]
assert!(75 == *cow1);
assert!(75 == *cow2);
- *cow0.make_unique() += 1;
+ unsafe {
+ *cow0.make_unique() += 1;
+ }
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
- *cow0.make_unique() += 1;
+ unsafe {
+ *cow0.make_unique() += 1;
+ }
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
//! You can get a non-`'static` `&str` by taking a slice of a `String`:
//!
//! ```
-//! # let some_string = "Hello, world.".to_string();
+//! let some_string = "Hello, world.".to_string();
//! let s = &some_string;
//! ```
//!
///
/// ```
/// let s = String::from("hello");
- /// let b: &[_] = &[104, 101, 108, 108, 111];
- /// assert_eq!(s.as_bytes(), b);
+ /// assert_eq!(s.as_bytes(), [104, 101, 108, 108, 111]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// ```{.should_panic}
/// let x: Option<&str> = None;
- /// x.expect("the world is ending"); // panics with `world is ending`
+ /// x.expect("the world is ending"); // panics with `the world is ending`
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Convert an `Option<String>` into an `Option<usize>`, consuming the original:
///
/// ```
- /// let num_as_str: Option<String> = Some("10".to_string());
- /// // `Option::map` takes self *by value*, consuming `num_as_str`
- /// let num_as_int: Option<usize> = num_as_str.map(|n| n.len());
+ /// let maybe_some_string = Some(String::from("Hello, World!"));
+ /// // `Option::map` takes self *by value*, consuming `maybe_some_string`
+ /// let maybe_some_len = maybe_some_string.map(|s| s.len());
+ ///
+ /// assert_eq!(maybe_some_len, Some(13));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- /// Applies a function to the contained value or returns a default.
+ /// Applies a function to the contained value (if any),
+ /// or returns a `default` (if not).
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
+ pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Some(t) => f(t),
- None => def
+ None => default,
}
}
- /// Applies a function to the contained value or computes a default.
+ /// Applies a function to the contained value (if any),
+ /// or computes a `default` (if not).
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, def: D, f: F) -> U {
+ pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
match self {
Some(t) => f(t),
- None => def()
+ None => default()
}
}
the heap at runtime, and therefore cannot be done at compile time.
"##,
+E0011: r##"
+Initializers for constants and statics are evaluated at compile time.
+User-defined operators rely on user-defined functions, which cannot be evaluated
+at compile time.
+
+Bad example:
+
+```
+use std::ops::Index;
+
+struct Foo { a: u8 }
+
+impl Index<u8> for Foo {
+ type Output = u8;
+
+ fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
+}
+
+const a: Foo = Foo { a: 0u8 };
+const b: u8 = a[0]; // Index trait is defined by the user, bad!
+```
+
+Only operators on builtin types are allowed.
+
+Example:
+
+```
+const a: &'static [i32] = &[1, 2, 3];
+const b: i32 = a[0]; // Good!
+```
+"##,
+
E0013: r##"
Static and const variables can refer to other const variables. But a const
variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
register_diagnostics! {
- E0011,
E0014,
E0016,
E0017,
option_env!("CFG_VER_DATE")
}
-pub fn build_date_str() -> Option<&'static str> {
- option_env!("CFG_BUILD_DATE")
-}
-
/// Prints version information and returns None on success or an error
/// message on panic.
pub fn version(binary: &str, matches: &getopts::Matches) {
println!("binary: {}", binary);
println!("commit-hash: {}", unw(commit_hash_str()));
println!("commit-date: {}", unw(commit_date_str()));
- println!("build-date: {}", unw(build_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(release_str()));
}
font-size: 1em;
position: relative;
}
-/* Shift "where ..." part of method definition down a line */
-.content .method .where { display: block; }
+/* Shift "where ..." part of method or fn definition down a line */
+.content .method .where, .content .fn .where { display: block; }
/* Bit of whitespace to indent it */
-.content .method .where::before { content: ' '; }
+.content .method .where::before, .content .fn .where::before { content: ' '; }
.content .methods > div { margin-left: 40px; }
//! val: num.to_json(),
//! }).unwrap();
//! println!("data: {}", data);
-//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"};
+//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
//! }
//! ```
//!
// Returns a tuple of (key_offset, val_offset),
// from the start of a mallocated array.
+#[inline]
fn calculate_offsets(hashes_size: usize,
keys_size: usize, keys_align: usize,
vals_align: usize)
/// A parameter was incorrect.
#[stable(feature = "rust1", since = "1.0.0")]
InvalidInput,
+ /// Data not valid for the operation were encountered.
+ ///
+ /// Unlike `InvalidInput`, this typically means that the operation
+ /// parameters were valid, however the error was caused by malformed
+ /// input data.
+ #[stable(feature = "io_invalid_data", since = "1.2.0")]
+ InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
#[stable(feature = "rust1", since = "1.0.0")]
TimedOut,
let ret = f(g.s);
if str::from_utf8(&g.s[g.len..]).is_err() {
ret.and_then(|_| {
- Err(Error::new(ErrorKind::InvalidInput,
+ Err(Error::new(ErrorKind::InvalidData,
"stream did not contain valid UTF-8"))
})
} else {
///
/// assert_eq!(x.max(y), y);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f32) -> f32 {
///
/// assert_eq!(x.min(y), x);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f32) -> f32 {
///
/// assert_eq!(x.max(y), y);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f64) -> f64 {
///
/// assert_eq!(x.min(y), x);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f64) -> f64 {
}
fn invalid_encoding() -> io::Error {
- io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode")
+ io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
///
-/// See [LocalKey documentation](thread/struct.LocalKey.html) for more information.
+/// See [LocalKey documentation](thread/struct.LocalKey.html) for more
+/// information.
#[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: ::std::thread::LocalKey<$t> = {
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]
- static __KEY: ::std::thread::__LocalKeyInner<$t> =
- ::std::thread::__LocalKeyInner::new();
- fn __init() -> $t { $init }
- fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY }
- ::std::thread::LocalKey::new(__getit, __init)
- };
+ static $name: ::std::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: ::std::thread::LocalKey<$t> = {
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]
- static __KEY: ::std::thread::__LocalKeyInner<$t> =
- ::std::thread::__LocalKeyInner::new();
- fn __init() -> $t { $init }
- fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY }
- ::std::thread::LocalKey::new(__getit, __init)
- };
+ pub static $name: ::std::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: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init, #[]);
+ );
+ (pub static $name:ident: $t:ty = $init:expr) => (
+ pub static $name: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init, #[]);
+ );
+}
+
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals",
+ reason = "should not be necessary")]
+#[macro_export]
+#[allow_internal_unstable]
+macro_rules! __thread_local_inner {
+ ($t:ty, $init:expr, #[$($attr:meta),*]) => {{
+ $(#[$attr])*
+ static __KEY: ::std::thread::__LocalKeyInner<$t> =
+ ::std::thread::__LocalKeyInner::new();
+ fn __init() -> $t { $init }
+ fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY }
+ ::std::thread::LocalKey::new(__getit, __init)
+ }}
+}
+
/// Indicator of the state of a thread local storage key.
#[unstable(feature = "std_misc",
reason = "state querying was recently added")]
impl<T: 'static> LocalKey<T> {
#[doc(hidden)]
- pub const fn new(inner: fn() -> &'static __KeyInner<T>, init: fn() -> T) -> LocalKey<T> {
+ #[unstable(feature = "thread_local_internals",
+ reason = "recently added to create a key")]
+ pub const fn new(inner: fn() -> &'static __KeyInner<T>,
+ init: fn() -> T) -> LocalKey<T> {
LocalKey {
inner: inner,
init: init
}
}
-#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
+#[cfg(all(any(target_os = "macos", target_os = "linux"),
+ not(target_arch = "aarch64"),
+ not(no_elf_tls)))]
#[doc(hidden)]
mod imp {
use prelude::v1::*;
}
}
-#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
+#[cfg(any(not(any(target_os = "macos", target_os = "linux")),
+ target_arch = "aarch64",
+ no_elf_tls))]
#[doc(hidden)]
mod imp {
use prelude::v1::*;
/// This macro declares a `static` item on which methods are used to get and
/// set the value stored within.
///
-/// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more information.
+/// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more
+/// information.
#[macro_export]
#[allow_internal_unstable]
+#[cfg(not(no_elf_tls))]
macro_rules! scoped_thread_local {
(static $name:ident: $t:ty) => (
#[cfg_attr(not(any(windows,
);
}
+#[macro_export]
+#[allow_internal_unstable]
+#[cfg(no_elf_tls)]
+macro_rules! scoped_thread_local {
+ (static $name:ident: $t:ty) => (
+ static $name: ::std::thread::ScopedKey<$t> =
+ ::std::thread::ScopedKey::new();
+ );
+ (pub static $name:ident: $t:ty) => (
+ pub static $name: ::std::thread::ScopedKey<$t> =
+ ::std::thread::ScopedKey::new();
+ );
+}
+
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
target_os = "android",
target_os = "ios",
target_os = "openbsd",
- target_arch = "aarch64")))]
+ target_arch = "aarch64",
+ no_elf_tls)))]
mod imp {
use std::cell::Cell;
target_os = "android",
target_os = "ios",
target_os = "openbsd",
- target_arch = "aarch64"))]
+ target_arch = "aarch64",
+ no_elf_tls))]
mod imp {
use prelude::v1::*;