diff --git a/mk/tests.mk b/mk/tests.mk index 2fb33eb7db898..e9f1baa8d4ef0 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -569,6 +569,11 @@ ifeq ($(CFG_OSTYPE),apple-darwin) CTEST_DISABLE_debuginfo-gdb = "gdb on darwin needs root" endif +ifeq ($(findstring android, $(CFG_TARGET)), android) +CTEST_DISABLE_debuginfo-gdb = +CTEST_DISABLE_debuginfo-lldb = "lldb tests are disabled on android" +endif + # CTEST_DISABLE_NONSELFHOST_$(TEST_GROUP), if set, will cause that # test group to be disabled *unless* the target is able to build a # compiler (i.e. when the target triple is in the set of of host diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index eb9e2b24ac900..f5dd92f5a3dbe 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -29,7 +29,12 @@ and will be able to understand most Rust code and write more complex programs. In a similar fashion to "Intermediate," this section is full of individual, deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on the most complex features, as well as some things that -are only available in upcoming versions of Rust. +chapters focus on the most complex features, -After reading "Advanced," you'll be a Rust expert! +

Unstable

+ +In a similar fashion to "Intermediate," this section is full of individual, +deep-dive chapters, which stand alone and can be read in any order. + +This chapter contains things that are only available on the nightly channel of +Rust. diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 70c74825a072c..140086e32d080 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -36,6 +36,12 @@ * [FFI](ffi.md) * [Unsafe Code](unsafe.md) * [Advanced Macros](advanced-macros.md) +* [Unstable Rust](unstable.md) * [Compiler Plugins](plugins.md) + * [Inline Assembly](inline-assembly.md) + * [No stdlib](no-stdlib.md) + * [Intrinsics](intrinsics.md) + * [Lang items](lang-items.md) + * [Link args](link-args.md) * [Conclusion](conclusion.md) * [Glossary](glossary.md) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md index 86279f7f1a168..fef458caaaf33 100644 --- a/src/doc/trpl/advanced-macros.md +++ b/src/doc/trpl/advanced-macros.md @@ -206,8 +206,6 @@ the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton within Rust's macro system. ```rust -#![feature(trace_macros)] - macro_rules! bct { // cmd 0: d ... => ... (0, $($ps:tt),* ; $_d:tt) @@ -229,13 +227,6 @@ macro_rules! bct { ( $($ps:tt),* ; ) => (()); } - -fn main() { - trace_macros!(true); -# /* just check the definition - bct!(0, 0, 1, 1, 1 ; 1, 0, 1); -# */ -} ``` Exercise: use macros to reduce duplication in the above definition of the diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 695279e2d5bb6..3dff72b3794de 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -366,31 +366,6 @@ A few examples of how this model can be used are: On OSX, frameworks behave with the same semantics as a dynamic library. -## The `link_args` attribute - -There is one other way to tell rustc how to customize linking, and that is via -the `link_args` attribute. This attribute is applied to `extern` blocks and -specifies raw flags which need to get passed to the linker when producing an -artifact. An example usage would be: - -``` no_run -#![feature(link_args)] - -#[link_args = "-foo -bar -baz"] -extern {} -# fn main() {} -``` - -Note that this feature is currently hidden behind the `feature(link_args)` gate -because this is not a sanctioned way of performing linking. Right now rustc -shells out to the system linker, so it makes sense to provide extra command line -arguments, but this will not always be the case. In the future rustc may use -LLVM directly to link native libraries in which case `link_args` will have no -meaning. - -It is highly recommended to *not* use this attribute, and rather use the more -formal `#[link(...)]` attribute on `extern` blocks instead. - # Unsafe blocks Some operations, like dereferencing unsafe pointers or calling functions that have been marked diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md new file mode 100644 index 0000000000000..1a4592f980fa7 --- /dev/null +++ b/src/doc/trpl/inline-assembly.md @@ -0,0 +1,141 @@ +% Inline Assembly + +For extremely low-level manipulations and performance reasons, one +might wish to control the CPU directly. Rust supports using inline +assembly to do this via the `asm!` macro. The syntax roughly matches +that of GCC & Clang: + +```ignore +asm!(assembly template + : output operands + : input operands + : clobbers + : options + ); +``` + +Any use of `asm` is feature gated (requires `#![feature(asm)]` on the +crate to allow) and of course requires an `unsafe` block. + +> **Note**: the examples here are given in x86/x86-64 assembly, but +> all platforms are supported. + +## Assembly template + +The `assembly template` is the only required parameter and must be a +literal string (i.e. `""`) + +``` +#![feature(asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn foo() { + unsafe { + asm!("NOP"); + } +} + +// other platforms +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn foo() { /* ... */ } + +fn main() { + // ... + foo(); + // ... +} +``` + +(The `feature(asm)` and `#[cfg]`s are omitted from now on.) + +Output operands, input operands, clobbers and options are all optional +but you must add the right number of `:` if you skip them: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +asm!("xor %eax, %eax" + : + : + : "eax" + ); +# } } +``` + +Whitespace also doesn't matter: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +asm!("xor %eax, %eax" ::: "eax"); +# } } +``` + +## Operands + +Input and output operands follow the same format: `: +"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand +expressions must be mutable lvalues: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn add(a: i32, b: i32) -> i32 { + let mut c = 0; + unsafe { + asm!("add $2, $0" + : "=r"(c) + : "0"(a), "r"(b) + ); + } + c +} +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn add(a: i32, b: i32) -> i32 { a + b } + +fn main() { + assert_eq!(add(3, 14159), 14162) +} +``` + +## Clobbers + +Some instructions modify registers which might otherwise have held +different values so we use the clobbers list to indicate to the +compiler not to assume any values loaded into those registers will +stay valid. + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +// Put the value 0x200 in eax +asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); +# } } +``` + +Input and output registers need not be listed since that information +is already communicated by the given constraints. Otherwise, any other +registers used either implicitly or explicitly should be listed. + +If the assembly changes the condition code register `cc` should be +specified as one of the clobbers. Similarly, if the assembly modifies +memory, `memory` should also be specified. + +## Options + +The last section, `options` is specific to Rust. The format is comma +separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to +specify some extra info about the inline assembly: + +Current valid options are: + +1. *volatile* - specifying this is analogous to + `__asm__ __volatile__ (...)` in gcc/clang. +2. *alignstack* - certain instructions expect the stack to be + aligned a certain way (i.e. SSE) and specifying this indicates to + the compiler to insert its usual stack alignment code +3. *intel* - use intel syntax instead of the default AT&T. + diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md new file mode 100644 index 0000000000000..25f7c54493188 --- /dev/null +++ b/src/doc/trpl/intrinsics.md @@ -0,0 +1,25 @@ +% Intrinsics + +> **Note**: intrinsics will forever have an unstable interface, it is +> recommended to use the stable interfaces of libcore rather than intrinsics +> directly. + +These are imported as if they were FFI functions, with the special +`rust-intrinsic` ABI. For example, if one was in a freestanding +context, but wished to be able to `transmute` between types, and +perform efficient pointer arithmetic, one would import those functions +via a declaration like + +``` +# #![feature(intrinsics)] +# fn main() {} + +extern "rust-intrinsic" { + fn transmute(x: T) -> U; + + fn offset(dst: *const T, offset: isize) -> *const T; +} +``` + +As with any other FFI functions, these are always `unsafe` to call. + diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md new file mode 100644 index 0000000000000..30ab59cc0291a --- /dev/null +++ b/src/doc/trpl/lang-items.md @@ -0,0 +1,79 @@ +% Lang items + +> **Note**: lang items are often provided by crates in the Rust distribution, +> and lang items themselves have an unstable interface. It is recommended to use +> officially distributed crates instead of defining your own lang items. + +The `rustc` compiler has certain pluggable operations, that is, +functionality that isn't hard-coded into the language, but is +implemented in libraries, with a special marker to tell the compiler +it exists. The marker is the attribute `#[lang="..."]` and there are +various different values of `...`, i.e. various different 'lang +items'. + +For example, `Box` pointers require two lang items, one for allocation +and one for deallocation. A freestanding program that uses the `Box` +sugar for dynamic allocations via `malloc` and `free`: + +``` +#![feature(lang_items, box_syntax, start, no_std)] +#![no_std] + +extern crate libc; + +extern { + fn abort() -> !; +} + +#[lang = "owned_box"] +pub struct Box(*mut T); + +#[lang="exchange_malloc"] +unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { + let p = libc::malloc(size as libc::size_t) as *mut u8; + + // malloc failed + if p as usize == 0 { + abort(); + } + + p +} +#[lang="exchange_free"] +unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { + libc::free(ptr as *mut libc::c_void) +} + +#[start] +fn main(argc: isize, argv: *const *const u8) -> isize { + let x = box 1; + + 0 +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +``` + +Note the use of `abort`: the `exchange_malloc` lang item is assumed to +return a valid pointer, and so needs to do the check internally. + +Other features provided by lang items include: + +- overloadable operators via traits: the traits corresponding to the + `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all + marked with lang items; those specific four are `eq`, `ord`, + `deref`, and `add` respectively. +- stack unwinding and general failure; the `eh_personality`, `fail` + and `fail_bounds_checks` lang items. +- the traits in `std::marker` used to indicate types of + various kinds; lang items `send`, `sync` and `copy`. +- the marker types and variance indicators found in + `std::marker`; lang items `covariant_type`, + `contravariant_lifetime`, etc. + +Lang items are loaded lazily by the compiler; e.g. if one never uses +`Box` then there is no need to define functions for `exchange_malloc` +and `exchange_free`. `rustc` will emit an error when an item is needed +but not found in the current crate or any that it depends on. diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md new file mode 100644 index 0000000000000..ee5159afb8e6f --- /dev/null +++ b/src/doc/trpl/link-args.md @@ -0,0 +1,25 @@ +% Link args + +There is one other way to tell rustc how to customize linking, and that is via +the `link_args` attribute. This attribute is applied to `extern` blocks and +specifies raw flags which need to get passed to the linker when producing an +artifact. An example usage would be: + +``` no_run +#![feature(link_args)] + +#[link_args = "-foo -bar -baz"] +extern {} +# fn main() {} +``` + +Note that this feature is currently hidden behind the `feature(link_args)` gate +because this is not a sanctioned way of performing linking. Right now rustc +shells out to the system linker, so it makes sense to provide extra command line +arguments, but this will not always be the case. In the future rustc may use +LLVM directly to link native libraries in which case `link_args` will have no +meaning. + +It is highly recommended to *not* use this attribute, and rather use the more +formal `#[link(...)]` attribute on `extern` blocks instead. + diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md new file mode 100644 index 0000000000000..539a0729ba336 --- /dev/null +++ b/src/doc/trpl/no-stdlib.md @@ -0,0 +1,168 @@ +% No stdlib + +By default, `std` is linked to every Rust crate. In some contexts, +this is undesirable, and can be avoided with the `#![no_std]` +attribute attached to the crate. + +```ignore +// a minimal library +#![crate_type="lib"] +#![feature(no_std)] +#![no_std] +# // fn main() {} tricked you, rustdoc! +``` + +Obviously there's more to life than just libraries: one can use +`#[no_std]` with an executable, controlling the entry point is +possible in two ways: the `#[start]` attribute, or overriding the +default shim for the C `main` function with your own. + +The function marked `#[start]` is passed the command line parameters +in the same format as C: + +``` +#![feature(lang_items, start, no_std)] +#![no_std] + +// Pull in the system libc library for what crt0.o likely requires +extern crate libc; + +// Entry point for this program +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +// These functions and traits are used by the compiler, but not +// for a bare-bones hello world. These are normally +// provided by libstd. +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + +To override the compiler-inserted `main` shim, one has to disable it +with `#![no_main]` and then create the appropriate symbol with the +correct ABI and the correct name, which requires overriding the +compiler's name mangling too: + +```ignore +#![feature(no_std)] +#![no_std] +#![no_main] +#![feature(lang_items, start)] + +extern crate libc; + +#[no_mangle] // ensure that this symbol is called `main` in the output +pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + + +The compiler currently makes a few assumptions about symbols which are available +in the executable to call. Normally these functions are provided by the standard +library, but without it you must define your own. + +The first of these three functions, `stack_exhausted`, is invoked whenever stack +overflow is detected. This function has a number of restrictions about how it +can be called and what it must do, but if the stack limit register is not being +maintained then a thread always has an "infinite stack" and this function +shouldn't get triggered. + +The second of these three functions, `eh_personality`, is used by the +failure mechanisms of the compiler. This is often mapped to GCC's +personality function (see the +[libstd implementation](../std/rt/unwind/index.html) for more +information), but crates which do not trigger a panic can be assured +that this function is never called. The final function, `panic_fmt`, is +also used by the failure mechanisms of the compiler. + +## Using libcore + +> **Note**: the core library's structure is unstable, and it is recommended to +> use the standard library instead wherever possible. + +With the above techniques, we've got a bare-metal executable running some Rust +code. There is a good deal of functionality provided by the standard library, +however, that is necessary to be productive in Rust. If the standard library is +not sufficient, then [libcore](../core/index.html) is designed to be used +instead. + +The core library has very few dependencies and is much more portable than the +standard library itself. Additionally, the core library has most of the +necessary functionality for writing idiomatic and effective Rust code. + +As an example, here is a program that will calculate the dot product of two +vectors provided from C, using idiomatic Rust practices. + +``` +#![feature(lang_items, start, no_std)] +#![no_std] + +# extern crate libc; +extern crate core; + +use core::prelude::*; + +use core::mem; + +#[no_mangle] +pub extern fn dot_product(a: *const u32, a_len: u32, + b: *const u32, b_len: u32) -> u32 { + use core::raw::Slice; + + // Convert the provided arrays into Rust slices. + // The core::raw module guarantees that the Slice + // structure has the same memory layout as a &[T] + // slice. + // + // This is an unsafe operation because the compiler + // cannot tell the pointers are valid. + let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { + mem::transmute(( + Slice { data: a, len: a_len as usize }, + Slice { data: b, len: b_len as usize }, + )) + }; + + // Iterate over the slices, collecting the result + let mut ret = 0; + for (i, j) in a_slice.iter().zip(b_slice.iter()) { + ret += (*i) * (*j); + } + return ret; +} + +#[lang = "panic_fmt"] +extern fn panic_fmt(args: &core::fmt::Arguments, + file: &str, + line: u32) -> ! { + loop {} +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } +# fn main() {} +``` + +Note that there is one extra lang item here which differs from the examples +above, `panic_fmt`. This must be defined by consumers of libcore because the +core library declares panics, but it does not define it. The `panic_fmt` +lang item is this crate's definition of panic, and it must be guaranteed to +never return. + +As can be seen in this example, the core library is intended to provide the +power of Rust in all circumstances, regardless of platform requirements. Further +libraries, such as liballoc, add functionality to libcore which make other +platform-specific assumptions, but continue to be more portable than the +standard library itself. + diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 33f0893466da6..9eb22a7f6985a 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -1,29 +1,5 @@ % Compiler Plugins -
- -

-Warning: Plugins are an advanced, unstable feature! For many details, -the only available documentation is the libsyntax and librustc API docs, or even the source -code itself. These internal compiler APIs are also subject to change at any -time. -

- -

-For defining new syntax it is often much easier to use Rust's built-in macro system. -

- -

-The code in this document uses language features not covered in the Rust -Guide. See the Reference Manual for more -information. -

- -
- # Introduction `rustc` can load compiler plugins, which are user-provided libraries that diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md index bd9b449fc087e..107d7d979a09c 100644 --- a/src/doc/trpl/pointers.md +++ b/src/doc/trpl/pointers.md @@ -568,8 +568,8 @@ fn add(x: &i32, y: &i32) -> i32 { fn main() { let x = Box::new(5); - println!("{}", add(&x, &x)); - println!("{}", add(&x, &x)); + println!("{}", add(&*x, &*x)); + println!("{}", add(&*x, &*x)); } ``` diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md new file mode 100644 index 0000000000000..bc337f30515a8 --- /dev/null +++ b/src/doc/trpl/tracing-macros.md @@ -0,0 +1,90 @@ +% Tracing Macros + +The `trace_macros` feature allows you to use a special feature: tracing macro +invocations. + +In the advanced macros chapter, we defined a `bct` macro: + +```rust +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} +``` + +This is pretty complex! we can see the output + + ```rust +#![feature(trace_macros)] + +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} + +fn main() { + trace_macros!(true); + + bct!(0, 0, 1, 1, 1 ; 1, 0, 1); +} + +This will print out a wall of text: + +```text +bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 } +bct! { 1 , 1 , 1 , 0 , 0 ; 1 } +bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 } +bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 } +bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 } +bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 } +bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 } +bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 } +``` + +And eventually, error: + +```text +18:45 error: recursion limit reached while expanding the macro `bct` + => (bct!($($ps),*, 1, $p ; $($ds),*)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +The `trace_macros!` call is what produces this output, showing how we match +each time. diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index dbf0cae6f4ba8..3ca3cfd05886e 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -181,539 +181,3 @@ code: that clean-up is always run, even when the thread panics. - ensure that any data stored behind a raw pointer is destroyed at the appropriate time. - -As an example, we give a reimplementation of owned boxes by wrapping -`malloc` and `free`. Rust's move semantics and lifetimes mean this -reimplementation is as safe as the `Box` type. - -``` -# #![feature(libc)] -#![feature(unsafe_destructor)] - -extern crate libc; -use libc::{c_void, size_t, malloc, free}; -use std::mem; -use std::ptr; - -// Define a wrapper around the handle returned by the foreign code. -// Unique has the same semantics as Box -// -// NB: For simplicity and correctness, we require that T has kind Send -// (owned boxes relax this restriction). -pub struct Unique { - // It contains a single raw, mutable pointer to the object in question. - ptr: *mut T -} - -// Implement methods for creating and using the values in the box. - -impl Unique { - pub fn new(value: T) -> Unique { - unsafe { - let ptr = malloc(mem::size_of::() as size_t) as *mut T; - // we *need* valid pointer. - assert!(!ptr.is_null()); - // `*ptr` is uninitialized, and `*ptr = value` would - // attempt to destroy it `overwrite` moves a value into - // this memory without attempting to drop the original - // value. - ptr::write(&mut *ptr, value); - Unique{ptr: ptr} - } - } - - // the 'r lifetime results in the same semantics as `&*x` with - // Box - pub fn borrow<'r>(&'r self) -> &'r T { - // By construction, self.ptr is valid - unsafe { &*self.ptr } - } - - // the 'r lifetime results in the same semantics as `&mut *x` with - // Box - pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T { - unsafe { &mut *self.ptr } - } -} - -// A key ingredient for safety, we associate a destructor with -// Unique, making the struct manage the raw pointer: when the -// struct goes out of scope, it will automatically free the raw pointer. -// -// NB: This is an unsafe destructor; rustc will not normally allow -// destructors to be associated with parameterized types (due to -// historically failing to check them soundly). Note that the -// `#[unsafe_destructor]` feature gate is currently required to use -// unsafe destructors. -#[unsafe_destructor] -impl Drop for Unique { - fn drop(&mut self) { - unsafe { - // Copy the object out from the pointer onto the stack, - // where it is covered by normal Rust destructor semantics - // and cleans itself up, if necessary - ptr::read(self.ptr); - - // clean-up our allocation - free(self.ptr as *mut c_void) - } - } -} - -// A comparison between the built-in `Box` and this reimplementation -fn main() { - { - let mut x = Box::new(5); - *x = 10; - } // `x` is freed here - - { - let mut y = Unique::new(5); - *y.borrow_mut() = 10; - } // `y` is freed here -} -``` - -Notably, the only way to construct a `Unique` is via the `new` -function, and this function ensures that the internal pointer is valid -and hidden in the private field. The two `borrow` methods are safe -because the compiler statically guarantees that objects are never used -before creation or after destruction (unless you use some `unsafe` -code...). - -# Inline assembly - -For extremely low-level manipulations and performance reasons, one -might wish to control the CPU directly. Rust supports using inline -assembly to do this via the `asm!` macro. The syntax roughly matches -that of GCC & Clang: - -```ignore -asm!(assembly template - : output operands - : input operands - : clobbers - : options - ); -``` - -Any use of `asm` is feature gated (requires `#![feature(asm)]` on the -crate to allow) and of course requires an `unsafe` block. - -> **Note**: the examples here are given in x86/x86-64 assembly, but -> all platforms are supported. - -## Assembly template - -The `assembly template` is the only required parameter and must be a -literal string (i.e. `""`) - -``` -#![feature(asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn foo() { - unsafe { - asm!("NOP"); - } -} - -// other platforms -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn foo() { /* ... */ } - -fn main() { - // ... - foo(); - // ... -} -``` - -(The `feature(asm)` and `#[cfg]`s are omitted from now on.) - -Output operands, input operands, clobbers and options are all optional -but you must add the right number of `:` if you skip them: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -asm!("xor %eax, %eax" - : - : - : "eax" - ); -# } } -``` - -Whitespace also doesn't matter: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -asm!("xor %eax, %eax" ::: "eax"); -# } } -``` - -## Operands - -Input and output operands follow the same format: `: -"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand -expressions must be mutable lvalues: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn add(a: i32, b: i32) -> i32 { - let mut c = 0; - unsafe { - asm!("add $2, $0" - : "=r"(c) - : "0"(a), "r"(b) - ); - } - c -} -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn add(a: i32, b: i32) -> i32 { a + b } - -fn main() { - assert_eq!(add(3, 14159), 14162) -} -``` - -## Clobbers - -Some instructions modify registers which might otherwise have held -different values so we use the clobbers list to indicate to the -compiler not to assume any values loaded into those registers will -stay valid. - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -// Put the value 0x200 in eax -asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); -# } } -``` - -Input and output registers need not be listed since that information -is already communicated by the given constraints. Otherwise, any other -registers used either implicitly or explicitly should be listed. - -If the assembly changes the condition code register `cc` should be -specified as one of the clobbers. Similarly, if the assembly modifies -memory, `memory` should also be specified. - -## Options - -The last section, `options` is specific to Rust. The format is comma -separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to -specify some extra info about the inline assembly: - -Current valid options are: - -1. *volatile* - specifying this is analogous to - `__asm__ __volatile__ (...)` in gcc/clang. -2. *alignstack* - certain instructions expect the stack to be - aligned a certain way (i.e. SSE) and specifying this indicates to - the compiler to insert its usual stack alignment code -3. *intel* - use intel syntax instead of the default AT&T. - -# Avoiding the standard library - -By default, `std` is linked to every Rust crate. In some contexts, -this is undesirable, and can be avoided with the `#![no_std]` -attribute attached to the crate. - -```ignore -// a minimal library -#![crate_type="lib"] -#![feature(no_std)] -#![no_std] -# // fn main() {} tricked you, rustdoc! -``` - -Obviously there's more to life than just libraries: one can use -`#[no_std]` with an executable, controlling the entry point is -possible in two ways: the `#[start]` attribute, or overriding the -default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -``` -# #![feature(libc)] -#![feature(lang_items, start, no_std)] -#![no_std] - -// Pull in the system libc library for what crt0.o likely requires -extern crate libc; - -// Entry point for this program -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions and traits are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```ignore -# #![feature(libc)] -#![feature(no_std)] -#![no_std] -#![no_main] -#![feature(lang_items, start)] - -extern crate libc; - -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { - 0 -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - - -The compiler currently makes a few assumptions about symbols which are available -in the executable to call. Normally these functions are provided by the standard -library, but without it you must define your own. - -The first of these three functions, `stack_exhausted`, is invoked whenever stack -overflow is detected. This function has a number of restrictions about how it -can be called and what it must do, but if the stack limit register is not being -maintained then a thread always has an "infinite stack" and this function -shouldn't get triggered. - -The second of these three functions, `eh_personality`, is used by the -failure mechanisms of the compiler. This is often mapped to GCC's -personality function (see the -[libstd implementation](../std/rt/unwind/index.html) for more -information), but crates which do not trigger a panic can be assured -that this function is never called. The final function, `panic_fmt`, is -also used by the failure mechanisms of the compiler. - -## Using libcore - -> **Note**: the core library's structure is unstable, and it is recommended to -> use the standard library instead wherever possible. - -With the above techniques, we've got a bare-metal executable running some Rust -code. There is a good deal of functionality provided by the standard library, -however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/index.html) is designed to be used -instead. - -The core library has very few dependencies and is much more portable than the -standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. - -As an example, here is a program that will calculate the dot product of two -vectors provided from C, using idiomatic Rust practices. - -``` -# #![feature(libc, core)] -#![feature(lang_items, start, no_std)] -#![no_std] - -# extern crate libc; -extern crate core; - -use core::prelude::*; - -use core::mem; - -#[no_mangle] -pub extern fn dot_product(a: *const u32, a_len: u32, - b: *const u32, b_len: u32) -> u32 { - use core::raw::Slice; - - // Convert the provided arrays into Rust slices. - // The core::raw module guarantees that the Slice - // structure has the same memory layout as a &[T] - // slice. - // - // This is an unsafe operation because the compiler - // cannot tell the pointers are valid. - let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { - mem::transmute(( - Slice { data: a, len: a_len as usize }, - Slice { data: b, len: b_len as usize }, - )) - }; - - // Iterate over the slices, collecting the result - let mut ret = 0; - for (i, j) in a_slice.iter().zip(b_slice.iter()) { - ret += (*i) * (*j); - } - return ret; -} - -#[lang = "panic_fmt"] -extern fn panic_fmt(args: &core::fmt::Arguments, - file: &str, - line: u32) -> ! { - loop {} -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } -# fn main() {} -``` - -Note that there is one extra lang item here which differs from the examples -above, `panic_fmt`. This must be defined by consumers of libcore because the -core library declares panics, but it does not define it. The `panic_fmt` -lang item is this crate's definition of panic, and it must be guaranteed to -never return. - -As can be seen in this example, the core library is intended to provide the -power of Rust in all circumstances, regardless of platform requirements. Further -libraries, such as liballoc, add functionality to libcore which make other -platform-specific assumptions, but continue to be more portable than the -standard library itself. - -# Interacting with the compiler internals - -> **Note**: this section is specific to the `rustc` compiler; these -> parts of the language may never be fully specified and so details may -> differ wildly between implementations (and even versions of `rustc` -> itself). -> -> Furthermore, this is just an overview; the best form of -> documentation for specific instances of these features are their -> definitions and uses in `std`. - -The Rust language currently has two orthogonal mechanisms for allowing -libraries to interact directly with the compiler and vice versa: - -- intrinsics, functions built directly into the compiler providing - very basic low-level functionality, -- lang-items, special functions, types and traits in libraries marked - with specific `#[lang]` attributes - -## Intrinsics - -> **Note**: intrinsics will forever have an unstable interface, it is -> recommended to use the stable interfaces of libcore rather than intrinsics -> directly. - -These are imported as if they were FFI functions, with the special -`rust-intrinsic` ABI. For example, if one was in a freestanding -context, but wished to be able to `transmute` between types, and -perform efficient pointer arithmetic, one would import those functions -via a declaration like - -``` -# #![feature(intrinsics)] -# fn main() {} - -extern "rust-intrinsic" { - fn transmute(x: T) -> U; - - fn offset(dst: *const T, offset: isize) -> *const T; -} -``` - -As with any other FFI functions, these are always `unsafe` to call. - -## Lang items - -> **Note**: lang items are often provided by crates in the Rust distribution, -> and lang items themselves have an unstable interface. It is recommended to use -> officially distributed crates instead of defining your own lang items. - -The `rustc` compiler has certain pluggable operations, that is, -functionality that isn't hard-coded into the language, but is -implemented in libraries, with a special marker to tell the compiler -it exists. The marker is the attribute `#[lang="..."]` and there are -various different values of `...`, i.e. various different 'lang -items'. - -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: - -``` -# #![feature(libc)] -#![feature(lang_items, box_syntax, start, no_std)] -#![no_std] - -extern crate libc; - -extern { - fn abort() -> !; -} - -#[lang = "owned_box"] -pub struct Box(*mut T); - -#[lang="exchange_malloc"] -unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; - - // malloc failed - if p as usize == 0 { - abort(); - } - - p -} -#[lang="exchange_free"] -unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { - libc::free(ptr as *mut libc::c_void) -} - -#[start] -fn main(argc: isize, argv: *const *const u8) -> isize { - let x = box 1; - - 0 -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -``` - -Note the use of `abort`: the `exchange_malloc` lang item is assumed to -return a valid pointer, and so needs to do the check internally. - -Other features provided by lang items include: - -- overloadable operators via traits: the traits corresponding to the - `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all - marked with lang items; those specific four are `eq`, `ord`, - `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, `fail` - and `fail_bounds_checks` lang items. -- the traits in `std::marker` used to indicate types of - various kinds; lang items `send`, `sync` and `copy`. -- the marker types and variance indicators found in - `std::marker`; lang items `covariant_type`, - `contravariant_lifetime`, etc. - -Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `exchange_free`. `rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 688d730e25287..83e632e6c9676 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -611,9 +611,11 @@ impl [T] { core_slice::SliceExt::get_mut(self, index) } - /// Work with `self` as a mut slice. - /// Primarily intended for getting a &mut [T] from a [T; N]. - #[stable(feature = "rust1", since = "1.0.0")] + /// Deprecated: use `&mut s[..]` instead. + #[unstable(feature = "collections", + reason = "will be replaced by slice syntax")] + #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] + #[allow(deprecated)] pub fn as_mut_slice(&mut self) -> &mut [T] { core_slice::SliceExt::as_mut_slice(self) } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e71077c96c774..19b0d5b166786 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -423,24 +423,13 @@ impl Vec { } } - /// Returns a mutable slice of the elements of `self`. - /// - /// # Examples - /// - /// ``` - /// fn foo(slice: &mut [i32]) {} - /// - /// let mut vec = vec![1, 2]; - /// foo(vec.as_mut_slice()); - /// ``` + /// Deprecated: use `&mut s[..]` instead. #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "collections", + reason = "will be replaced by slice syntax")] + #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] pub fn as_mut_slice(&mut self) -> &mut [T] { - unsafe { - let ptr = *self.ptr; - assume(!ptr.is_null()); - slice::from_raw_parts_mut(ptr, self.len) - } + &mut self[..] } /// Creates a consuming iterator, that is, one that moves each value out of @@ -1494,13 +1483,13 @@ impl ops::IndexMut for Vec { #[cfg(stage0)] #[inline] fn index_mut(&mut self, _index: &ops::RangeFull) -> &mut [T] { - self.as_mut_slice() + self } #[cfg(not(stage0))] #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] { - self.as_mut_slice() + self } } @@ -1519,7 +1508,13 @@ impl ops::Deref for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl ops::DerefMut for Vec { - fn deref_mut(&mut self) -> &mut [T] { self.as_mut_slice() } + fn deref_mut(&mut self) -> &mut [T] { + unsafe { + let ptr = *self.ptr; + assume(!ptr.is_null()); + slice::from_raw_parts_mut(ptr, self.len) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1656,21 +1651,13 @@ impl Ord for Vec { } } +#[unstable(feature = "collections", + reason = "will be replaced by slice syntax")] +#[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] #[allow(deprecated)] impl AsSlice for Vec { - /// Returns a slice into `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// fn foo(slice: &[i32]) {} - /// - /// let vec = vec![1, 2]; - /// foo(vec.as_slice()); - /// ``` + /// Deprecated: use `&mut s[..]` instead. #[inline] - #[stable(feature = "rust1", since = "1.0.0")] fn as_slice(&self) -> &[T] { self } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index fee40115f3952..16d03901239b3 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -995,8 +995,10 @@ impl fmt::Debug for RangeFull { #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { /// The lower bound of the range (inclusive). + #[stable(feature = "rust1", since = "1.0.0")] pub start: Idx, /// The upper bound of the range (exclusive). + #[stable(feature = "rust1", since = "1.0.0")] pub end: Idx, } @@ -1013,11 +1015,10 @@ impl fmt::Debug for Range { #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { /// The lower bound of the range (inclusive). + #[stable(feature = "rust1", since = "1.0.0")] pub start: Idx, } - - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for RangeFrom { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { @@ -1031,6 +1032,7 @@ impl fmt::Debug for RangeFrom { #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { /// The upper bound of the range (exclusive). + #[stable(feature = "rust1", since = "1.0.0")] pub end: Idx, } @@ -1041,7 +1043,6 @@ impl fmt::Debug for RangeTo { } } - /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. /// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index fce29abed7300..892660b98bc95 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -88,6 +88,9 @@ pub trait SliceExt { fn len(&self) -> usize; fn is_empty(&self) -> bool { self.len() == 0 } fn get_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut Self::Item>; + #[unstable(feature = "core", + reason = "will be replaced by slice syntax")] + #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] fn as_mut_slice<'a>(&'a mut self) -> &'a mut [Self::Item]; fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Self::Item>; fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>; @@ -261,6 +264,9 @@ impl SliceExt for [T] { } #[inline] + #[unstable(feature = "core", + reason = "will be replaced by slice syntax")] + #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] fn as_mut_slice(&mut self) -> &mut [T] { self } #[cfg(stage0)] diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index 16298240acfbe..ce03e26866b7d 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -24,38 +24,58 @@ use vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] impl<'a, R: Read + ?Sized> Read for &'a mut R { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } + + #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) } + + #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { (**self).read_to_string(buf) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, W: Write + ?Sized> Write for &'a mut W { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() } + + #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { (**self).write_all(buf) } + + #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { (**self).write_fmt(fmt) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, S: Seek + ?Sized> Seek for &'a mut S { + #[inline] fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + + #[inline] fn consume(&mut self, amt: usize) { (**self).consume(amt) } + + #[inline] fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { (**self).read_until(byte, buf) } + + #[inline] fn read_line(&mut self, buf: &mut String) -> io::Result { (**self).read_line(buf) } @@ -63,38 +83,58 @@ impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { #[stable(feature = "rust1", since = "1.0.0")] impl Read for Box { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } + + #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) } + + #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { (**self).read_to_string(buf) } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for Box { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() } + + #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { (**self).write_all(buf) } + + #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { (**self).write_fmt(fmt) } } #[stable(feature = "rust1", since = "1.0.0")] impl Seek for Box { + #[inline] fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } } #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Box { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + + #[inline] fn consume(&mut self, amt: usize) { (**self).consume(amt) } + + #[inline] fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { (**self).read_until(byte, buf) } + + #[inline] fn read_line(&mut self, buf: &mut String) -> io::Result { (**self).read_line(buf) } @@ -105,6 +145,7 @@ impl BufRead for Box { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for &'a [u8] { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { let amt = cmp::min(buf.len(), self.len()); let (a, b) = self.split_at(amt); @@ -116,12 +157,16 @@ impl<'a> Read for &'a [u8] { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> BufRead for &'a [u8] { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } + + #[inline] fn consume(&mut self, amt: usize) { *self = &self[amt..]; } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for &'a mut [u8] { + #[inline] fn write(&mut self, data: &[u8]) -> io::Result { let amt = cmp::min(data.len(), self.len()); let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); @@ -130,6 +175,7 @@ impl<'a> Write for &'a mut [u8] { Ok(amt) } + #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { if try!(self.write(data)) == data.len() { Ok(()) @@ -138,20 +184,87 @@ impl<'a> Write for &'a mut [u8] { } } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for Vec { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.push_all(buf); Ok(buf.len()) } + #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.push_all(buf); Ok(()) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } + +#[cfg(test)] +mod tests { + use io::prelude::*; + use vec::Vec; + use test; + + #[bench] + fn bench_read_slice(b: &mut test::Bencher) { + let buf = [5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in (0 .. 8) { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) + } + + #[bench] + fn bench_write_slice(b: &mut test::Bencher) { + let mut buf = [0; 1024]; + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in (0 .. 8) { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) + } + + #[bench] + fn bench_read_vec(b: &mut test::Bencher) { + let buf = vec![5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in (0 .. 8) { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) + } + + #[bench] + fn bench_write_vec(b: &mut test::Bencher) { + let mut buf = Vec::with_capacity(1024); + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in (0 .. 8) { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) + } +} diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index e8187dc2c4027..dafca974bec0e 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -15,7 +15,7 @@ use hash; use io; use libc::{self, socklen_t, sa_family_t}; use mem; -use net::{lookup_host, ntoh, hton, Ipv4Addr, Ipv6Addr}; +use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; use option; use sys_common::{FromInner, AsInner, IntoInner}; use vec; @@ -47,6 +47,15 @@ pub struct SocketAddrV4 { inner: libc::sockaddr_in } pub struct SocketAddrV6 { inner: libc::sockaddr_in6 } impl SocketAddr { + /// Gets the IP address associated with this socket address. + #[unstable(feature = "ip_addr", reason = "recent addition")] + pub fn ip(&self) -> IpAddr { + match *self { + SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), + SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), + } + } + /// Gets the port number associated with this socket address #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { @@ -333,6 +342,18 @@ impl ToSocketAddrs for SocketAddrV6 { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (IpAddr, u16) { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (ip, port) = *self; + match ip { + IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), + IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ToSocketAddrs for (Ipv4Addr, u16) { type Iter = option::IntoIter; diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index d737ad17ff8ec..c8b1928747705 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,6 +21,16 @@ use libc; use sys_common::{AsInner, FromInner}; use net::{hton, ntoh}; +/// An IP address, either a IPv4 or IPv6 address. +#[unstable(feature = "ip_addr", reason = "recent addition")] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// Representation of an IPv4 address. + V4(Ipv4Addr), + /// Representation of an IPv6 address. + V6(Ipv6Addr), +} + /// Representation of an IPv4 address. #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] @@ -139,6 +149,16 @@ impl Ipv4Addr { } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpAddr::V4(ref a) => a.fmt(fmt), + IpAddr::V6(ref a) => a.fmt(fmt), + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 48b3247f2127a..7f51b1cba3fe7 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -21,7 +21,7 @@ use io::{self, Error, ErrorKind}; use num::Int; use sys_common::net2 as net_imp; -pub use self::ip::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; pub use self::tcp::{TcpStream, TcpListener}; pub use self::udp::UdpSocket; @@ -74,10 +74,14 @@ fn each_addr(addr: A, mut f: F) -> io::Result } /// An iterator over `SocketAddr` values returned from a host lookup operation. -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses")] pub struct LookupHost(net_imp::LookupHost); -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses")] impl Iterator for LookupHost { type Item = io::Result; fn next(&mut self) -> Option> { self.0.next() } @@ -91,7 +95,7 @@ impl Iterator for LookupHost { /// # Examples /// /// ```no_run -/// # #![feature(net)] +/// # #![feature(lookup_host)] /// use std::net; /// /// # fn foo() -> std::io::Result<()> { @@ -101,7 +105,9 @@ impl Iterator for LookupHost { /// # Ok(()) /// # } /// ``` -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "lookup_host", reason = "unsure about the returned \ + iterator and returning socket \ + addresses")] pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index e593bbe8e489b..811511149628e 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -14,7 +14,7 @@ use prelude::v1::*; use io::{self, Error, ErrorKind}; -use net::{ToSocketAddrs, SocketAddr}; +use net::{ToSocketAddrs, SocketAddr, IpAddr}; use sys_common::net2 as net_imp; use sys_common::AsInner; @@ -116,12 +116,12 @@ impl UdpSocket { } /// Joins a multicast IP address (becomes a member of it) - pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> { + pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { self.0.join_multicast(multi) } /// Leaves a multicast IP address (drops membership from it) - pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> { + pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { self.0.leave_multicast(multi) } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 553412c83712f..6a36ecefcf446 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -748,6 +748,7 @@ mod tests { cmd } + #[cfg(not(target_arch = "aarch64"))] #[test] fn test_keep_current_working_dir() { use os; diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index 25aeab1b4ff74..e213a86644fe1 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -14,7 +14,7 @@ use ffi::CString; use io::{self, Error, ErrorKind}; use libc::{self, c_int, c_char, c_void, socklen_t}; use mem; -use net::{SocketAddr, Shutdown}; +use net::{SocketAddr, Shutdown, IpAddr}; use sys::c; use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; use sys_common::{AsInner, FromInner, IntoInner}; @@ -334,39 +334,39 @@ impl UdpSocket { libc::IP_MULTICAST_LOOP, on as c_int) } - pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> { + pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { match *multi { - SocketAddr::V4(..) => { + IpAddr::V4(..) => { self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) } - SocketAddr::V6(..) => { + IpAddr::V6(..) => { self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) } } } - pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> { + pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { match *multi { - SocketAddr::V4(..) => { + IpAddr::V4(..) => { self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) } - SocketAddr::V6(..) => { + IpAddr::V6(..) => { self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) } } } - fn set_membership(&self, addr: &SocketAddr, opt: c_int) -> io::Result<()> { + fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> { match *addr { - SocketAddr::V4(ref addr) => { + IpAddr::V4(ref addr) => { let mreq = libc::ip_mreq { - imr_multiaddr: *addr.ip().as_inner(), + imr_multiaddr: *addr.as_inner(), // interface == INADDR_ANY imr_interface: libc::in_addr { s_addr: 0x0 }, }; setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq) } - SocketAddr::V6(ref addr) => { + IpAddr::V6(ref addr) => { let mreq = libc::ip6_mreq { - ipv6mr_multiaddr: *addr.ip().as_inner(), + ipv6mr_multiaddr: *addr.as_inner(), ipv6mr_interface: 0, }; setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 58b6d96607df7..0c5e4d67642ac 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -332,6 +332,46 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) RefCell::new(f) } +/// This method helps to extract all the type parameters referenced from a +/// type. For a type parameter ``, it looks for either a `TyPath` that +/// is not global and starts with `T`, or a `TyQPath`. +fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec> { + use visit; + + struct Visitor<'a> { + ty_param_names: &'a [ast::Name], + types: Vec>, + } + + impl<'a> visit::Visitor<'a> for Visitor<'a> { + fn visit_ty(&mut self, ty: &'a ast::Ty) { + match ty.node { + ast::TyPath(_, ref path) if !path.global => { + match path.segments.first() { + Some(segment) => { + if self.ty_param_names.contains(&segment.identifier.name) { + self.types.push(P(ty.clone())); + } + } + None => {} + } + } + _ => {} + } + + visit::walk_ty(self, ty) + } + } + + let mut visitor = Visitor { + ty_param_names: ty_param_names, + types: Vec::new(), + }; + + visit::Visitor::visit_ty(&mut visitor, ty); + + visitor.types +} impl<'a> TraitDef<'a> { pub fn expand(&self, @@ -374,18 +414,42 @@ impl<'a> TraitDef<'a> { })) } - /// Given that we are deriving a trait `Tr` for a type `T<'a, ..., - /// 'z, A, ..., Z>`, creates an impl like: + /// Given that we are deriving a trait `DerivedTrait` for a type like: /// /// ```ignore - /// impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T { ... } + /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait { + /// a: A, + /// b: B::Item, + /// b1: ::Item, + /// c1: ::Item, + /// c2: Option<::Item>, + /// ... + /// } + /// ``` + /// + /// create an impl like: + /// + /// ```ignore + /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where + /// C: WhereTrait, + /// A: DerivedTrait + B1 + ... + BN, + /// B: DerivedTrait + B1 + ... + BN, + /// C: DerivedTrait + B1 + ... + BN, + /// B::Item: DerivedTrait + B1 + ... + BN, + /// ::Item: DerivedTrait + B1 + ... + BN, + /// ... + /// { + /// ... + /// } /// ``` /// - /// where B1, B2, ... are the bounds given by `bounds_paths`.' + /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and + /// therefore does not get bound by the derived trait. fn create_derived_impl(&self, cx: &mut ExtCtxt, type_ident: Ident, generics: &Generics, + field_tys: Vec>, methods: Vec>) -> P { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); @@ -466,6 +530,35 @@ impl<'a> TraitDef<'a> { } })); + if !ty_params.is_empty() { + let ty_param_names: Vec = ty_params.iter() + .map(|ty_param| ty_param.ident.name) + .collect(); + + for field_ty in field_tys.into_iter() { + let tys = find_type_parameters(&*field_ty, &ty_param_names); + + for ty in tys.into_iter() { + let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { + cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) + }).collect(); + + // require the current trait + bounds.push(cx.typarambound(trait_path.clone())); + + let predicate = ast::WhereBoundPredicate { + span: self.span, + bound_lifetimes: vec![], + bounded_ty: ty, + bounds: OwnedSlice::from_vec(bounds), + }; + + let predicate = ast::WherePredicate::BoundPredicate(predicate); + where_clause.predicates.push(predicate); + } + } + } + let trait_generics = Generics { lifetimes: lifetimes, ty_params: OwnedSlice::from_vec(ty_params), @@ -518,6 +611,10 @@ impl<'a> TraitDef<'a> { struct_def: &StructDef, type_ident: Ident, generics: &Generics) -> P { + let field_tys: Vec> = struct_def.fields.iter() + .map(|field| field.node.ty.clone()) + .collect(); + let methods = self.methods.iter().map(|method_def| { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args( @@ -550,7 +647,7 @@ impl<'a> TraitDef<'a> { body) }).collect(); - self.create_derived_impl(cx, type_ident, generics, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } fn expand_enum_def(&self, @@ -558,6 +655,21 @@ impl<'a> TraitDef<'a> { enum_def: &EnumDef, type_ident: Ident, generics: &Generics) -> P { + let mut field_tys = Vec::new(); + + for variant in enum_def.variants.iter() { + match variant.node.kind { + ast::VariantKind::TupleVariantKind(ref args) => { + field_tys.extend(args.iter() + .map(|arg| arg.ty.clone())); + } + ast::VariantKind::StructVariantKind(ref args) => { + field_tys.extend(args.fields.iter() + .map(|field| field.node.ty.clone())); + } + } + } + let methods = self.methods.iter().map(|method_def| { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, @@ -590,7 +702,7 @@ impl<'a> TraitDef<'a> { body) }).collect(); - self.create_derived_impl(cx, type_ident, generics, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } } diff --git a/src/test/auxiliary/struct_variant_xc_aux.rs b/src/test/auxiliary/struct_variant_xc_aux.rs index 76fd619f68964..8670cd96fc6de 100644 --- a/src/test/auxiliary/struct_variant_xc_aux.rs +++ b/src/test/auxiliary/struct_variant_xc_aux.rs @@ -11,6 +11,7 @@ #![crate_name="struct_variant_xc_aux"] #![crate_type = "lib"] +#[derive(Copy)] pub enum Enum { Variant(u8), StructVariant { arg: u8 } diff --git a/src/test/compile-fail/derive-assoc-type-not-impl.rs b/src/test/compile-fail/derive-assoc-type-not-impl.rs new file mode 100644 index 0000000000000..3799f2ffba440 --- /dev/null +++ b/src/test/compile-fail/derive-assoc-type-not-impl.rs @@ -0,0 +1,29 @@ +// 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. + +trait Foo { + type X; + fn method(&self) {} +} + +#[derive(Clone)] +struct Bar { + x: T::X, +} + +struct NotClone; + +impl Foo for NotClone { + type X = i8; +} + +fn main() { + Bar:: { x: 1 }.clone(); //~ ERROR +} diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 2305d7bc5c245..766105881cedf 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-aarch64 // min-lldb-version: 310 // compile-flags:-g diff --git a/src/test/debuginfo/issue12886.rs b/src/test/debuginfo/issue12886.rs index 424ba50e3c978..3c2e7f10d1611 100644 --- a/src/test/debuginfo/issue12886.rs +++ b/src/test/debuginfo/issue12886.rs @@ -10,12 +10,13 @@ // ignore-windows failing on 64-bit bots FIXME #17638 // ignore-lldb +// ignore-aarch64 // compile-flags:-g // gdb-command:run // gdb-command:next -// gdb-check:[...]33[...]s +// gdb-check:[...]34[...]s // gdb-command:continue #![omit_gdb_pretty_printer_section] diff --git a/src/test/run-pass/deriving-associated-types.rs b/src/test/run-pass/deriving-associated-types.rs new file mode 100644 index 0000000000000..59eb5506c45c7 --- /dev/null +++ b/src/test/run-pass/deriving-associated-types.rs @@ -0,0 +1,210 @@ +// 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. + +#![feature(core, debug_builders)] + +pub trait DeclaredTrait { + type Type; +} + +impl DeclaredTrait for i32 { + type Type = i32; +} + +pub trait WhereTrait { + type Type; +} + +impl WhereTrait for i32 { + type Type = i32; +} + +// Make sure we don't add a bound that just shares a name with an associated +// type. +pub mod module { + pub type Type = i32; +} + +#[derive(PartialEq, Debug)] +struct PrivateStruct(T); + +#[derive(PartialEq, Debug)] +struct TupleStruct( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, +) where C: WhereTrait; + +#[derive(PartialEq, Debug)] +pub struct Struct where C: WhereTrait { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::Type, +} + +#[derive(PartialEq, Debug)] +enum Enum where C: WhereTrait { + Unit, + Seq( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, + ), + Map { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::Type, + }, +} + +fn main() { + let e: TupleStruct< + i32, + i32, + i32, + > = TupleStruct( + 0, + None, + 0, + PrivateStruct(0), + 0, + 0, + None, + 0, + None, + 0, + 0, + None, + 0, + None, + 0, + ); + assert_eq!(e, e); + + let e: Struct< + i32, + i32, + i32, + > = Struct { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); + + let e = Enum::Unit::; + assert_eq!(e, e); + + let e: Enum< + i32, + i32, + i32, + > = Enum::Seq( + 0, + None, + 0, + PrivateStruct(0), + 0, + 0, + None, + 0, + None, + 0, + 0, + None, + 0, + None, + 0, + ); + assert_eq!(e, e); + + let e: Enum< + i32, + i32, + i32, + > = Enum::Map { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); +} diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs index b81d0f2407bf0..4a05b487ae24e 100644 --- a/src/test/run-pass/sigpipe-should-be-ignored.rs +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -11,6 +11,7 @@ // Be sure that when a SIGPIPE would have been received that the entire process // doesn't die in a ball of fire, but rather it's gracefully handled. +// ignore-aarch64 // pretty-expanded FIXME #23616 use std::env;