]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #41173 - GuillaumeGomez:fix-rustdoc-code-block-parsing, r=steveklabnik
authorCorey Farwell <coreyf@rwell.org>
Tue, 11 Apr 2017 22:36:13 +0000 (18:36 -0400)
committerGitHub <noreply@github.com>
Tue, 11 Apr 2017 22:36:13 +0000 (18:36 -0400)
Fix block code headers parsing

Fixes #41167.

r? @rust-lang/docs

210 files changed:
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/as-c-str.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-barriers.md [new file with mode: 0644]
src/doc/unstable-book/src/linker-flavor.md [new file with mode: 0644]
src/doc/unstable-book/src/manually-drop.md [new file with mode: 0644]
src/doc/unstable-book/src/str-mut-extras.md [new file with mode: 0644]
src/liballoc_jemalloc/build.rs
src/liballoc_jemalloc/lib.rs
src/libcollections/btree/map.rs
src/libcollections/enum_set.rs
src/libcollections/lib.rs
src/libcollections/range.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec_deque.rs
src/libcore/char.rs
src/libcore/cmp.rs
src/libcore/fmt/mod.rs
src/libcore/intrinsics.rs
src/libcore/mem.rs
src/libcore/ops.rs
src/libcore/slice/mod.rs
src/libcore/slice/sort.rs
src/libcore/str/mod.rs
src/libcore/sync/atomic.rs
src/libcore/tests/lib.rs
src/libcore/tests/slice.rs
src/librustc/middle/intrinsicck.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/ty/context.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc_back/lib.rs
src/librustc_back/target/aarch64_apple_ios.rs
src/librustc_back/target/aarch64_linux_android.rs
src/librustc_back/target/aarch64_unknown_freebsd.rs
src/librustc_back/target/aarch64_unknown_fuchsia.rs
src/librustc_back/target/aarch64_unknown_linux_gnu.rs
src/librustc_back/target/android_base.rs
src/librustc_back/target/apple_base.rs
src/librustc_back/target/apple_ios_base.rs
src/librustc_back/target/arm_linux_androideabi.rs
src/librustc_back/target/arm_unknown_linux_gnueabi.rs
src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
src/librustc_back/target/arm_unknown_linux_musleabi.rs
src/librustc_back/target/arm_unknown_linux_musleabihf.rs
src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
src/librustc_back/target/armv7_apple_ios.rs
src/librustc_back/target/armv7_linux_androideabi.rs
src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
src/librustc_back/target/armv7_unknown_linux_musleabihf.rs
src/librustc_back/target/armv7s_apple_ios.rs
src/librustc_back/target/asmjs_unknown_emscripten.rs
src/librustc_back/target/dragonfly_base.rs
src/librustc_back/target/freebsd_base.rs
src/librustc_back/target/fuchsia_base.rs
src/librustc_back/target/i386_apple_ios.rs
src/librustc_back/target/i686_apple_darwin.rs
src/librustc_back/target/i686_linux_android.rs
src/librustc_back/target/i686_pc_windows_gnu.rs
src/librustc_back/target/i686_pc_windows_msvc.rs
src/librustc_back/target/i686_unknown_dragonfly.rs
src/librustc_back/target/i686_unknown_freebsd.rs
src/librustc_back/target/i686_unknown_haiku.rs
src/librustc_back/target/i686_unknown_linux_gnu.rs
src/librustc_back/target/i686_unknown_linux_musl.rs
src/librustc_back/target/i686_unknown_netbsd.rs
src/librustc_back/target/i686_unknown_openbsd.rs
src/librustc_back/target/le32_unknown_nacl.rs
src/librustc_back/target/linux_base.rs
src/librustc_back/target/linux_musl_base.rs
src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
src/librustc_back/target/mips_unknown_linux_gnu.rs
src/librustc_back/target/mips_unknown_linux_musl.rs
src/librustc_back/target/mips_unknown_linux_uclibc.rs
src/librustc_back/target/mipsel_unknown_linux_gnu.rs
src/librustc_back/target/mipsel_unknown_linux_musl.rs
src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/netbsd_base.rs
src/librustc_back/target/openbsd_base.rs
src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
src/librustc_back/target/powerpc_unknown_linux_gnu.rs
src/librustc_back/target/redox_base.rs
src/librustc_back/target/s390x_unknown_linux_gnu.rs
src/librustc_back/target/sparc64_unknown_linux_gnu.rs
src/librustc_back/target/sparc64_unknown_netbsd.rs
src/librustc_back/target/sparcv9_sun_solaris.rs
src/librustc_back/target/thumbv6m_none_eabi.rs
src/librustc_back/target/thumbv7em_none_eabi.rs
src/librustc_back/target/thumbv7em_none_eabihf.rs
src/librustc_back/target/thumbv7m_none_eabi.rs
src/librustc_back/target/wasm32_unknown_emscripten.rs
src/librustc_back/target/windows_base.rs
src/librustc_back/target/windows_msvc_base.rs
src/librustc_back/target/x86_64_apple_darwin.rs
src/librustc_back/target/x86_64_apple_ios.rs
src/librustc_back/target/x86_64_pc_windows_gnu.rs
src/librustc_back/target/x86_64_pc_windows_msvc.rs
src/librustc_back/target/x86_64_rumprun_netbsd.rs
src/librustc_back/target/x86_64_sun_solaris.rs
src/librustc_back/target/x86_64_unknown_bitrig.rs
src/librustc_back/target/x86_64_unknown_dragonfly.rs
src/librustc_back/target/x86_64_unknown_freebsd.rs
src/librustc_back/target/x86_64_unknown_fuchsia.rs
src/librustc_back/target/x86_64_unknown_haiku.rs
src/librustc_back/target/x86_64_unknown_linux_gnu.rs
src/librustc_back/target/x86_64_unknown_linux_musl.rs
src/librustc_back/target/x86_64_unknown_netbsd.rs
src/librustc_back/target/x86_64_unknown_openbsd.rs
src/librustc_back/target/x86_64_unknown_redox.rs
src/librustc_data_structures/array_vec.rs
src/librustc_data_structures/lib.rs
src/librustc_driver/lib.rs
src/librustc_errors/emitter.rs
src/librustc_errors/snippet.rs
src/librustc_lint/types.rs
src/librustc_llvm/build.rs
src/librustc_trans/abi.rs
src/librustc_trans/adt.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/base.rs
src/librustc_trans/cabi_aarch64.rs
src/librustc_trans/cabi_arm.rs
src/librustc_trans/cabi_asmjs.rs
src/librustc_trans/cabi_mips.rs
src/librustc_trans/cabi_mips64.rs
src/librustc_trans/cabi_msp430.rs
src/librustc_trans/cabi_nvptx.rs
src/librustc_trans/cabi_nvptx64.rs
src/librustc_trans/cabi_powerpc.rs
src/librustc_trans/cabi_powerpc64.rs
src/librustc_trans/cabi_s390x.rs
src/librustc_trans/cabi_sparc.rs
src/librustc_trans/cabi_sparc64.rs
src/librustc_trans/cabi_x86.rs
src/librustc_trans/cabi_x86_64.rs
src/librustc_trans/cabi_x86_win64.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/glue.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/meth.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/check/intrinsic.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/rustdoc.css
src/libstd/ascii.rs
src/libstd/ffi/c_str.rs
src/libstd/lib.rs
src/libstd/process.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mutex.rs
src/libstd/sys_common/poison.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/parser.rs
src/libsyntax/test_snippet.rs
src/libsyntax_pos/lib.rs
src/test/codegen/function-arguments.rs
src/test/compile-fail/feature-gate-linker-flavor.rs [new file with mode: 0644]
src/test/compile-fail/forget-init-unsafe.rs
src/test/compile-fail/impl-trait/equality.rs [deleted file]
src/test/run-make/target-specs/my-awesome-platform.json
src/test/run-make/target-specs/my-incomplete-platform.json
src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json
src/test/run-pass/optimization-fuel-0.rs [new file with mode: 0644]
src/test/run-pass/optimization-fuel-1.rs [new file with mode: 0644]
src/test/run-pass/type-sizes.rs
src/test/rustdoc/impl-parts.rs
src/test/rustdoc/issue-20727-4.rs
src/test/rustdoc/where.rs
src/test/ui/impl-trait/equality.rs [new file with mode: 0644]
src/test/ui/impl-trait/equality.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/binops.rs [new file with mode: 0644]
src/test/ui/mismatched_types/binops.stderr [new file with mode: 0644]
src/test/ui/print-fuel/print-fuel.rs [new file with mode: 0644]
src/test/ui/print-fuel/print-fuel.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/nullable.stdout
src/test/ui/print_type_sizes/packed.stdout
src/test/ui/print_type_sizes/padding.stdout
src/test/ui/span/impl-wrong-item-for-trait.stderr
src/test/ui/span/issue-23729.stderr
src/test/ui/span/issue-23827.stderr
src/test/ui/span/multiline-span-simple.stderr
src/test/ui/token/issue-41155.rs [new file with mode: 0644]
src/test/ui/token/issue-41155.stderr [new file with mode: 0644]
src/tools/tidy/src/bins.rs
src/tools/tidy/src/cargo.rs
src/tools/tidy/src/errors.rs
src/tools/tidy/src/features.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/pal.rs
src/tools/tidy/src/style.rs
src/tools/tidy/src/unstable_book.rs

index 20812de524add29aa089e6bdd28dabcc08b5771a..54e602a81db7389e93e2eb682e8c2371ce423223 100644 (file)
@@ -12,6 +12,7 @@
 - [alloc_system](alloc-system.md)
 - [allocator](allocator.md)
 - [allow_internal_unstable](allow-internal-unstable.md)
+- [as_c_str](as-c-str.md)
 - [as_unsafe_cell](as-unsafe-cell.md)
 - [ascii_ctype](ascii-ctype.md)
 - [asm](asm.md)
@@ -37,6 +38,7 @@
 - [collections](collections.md)
 - [collections_range](collections-range.md)
 - [command_envs](command-envs.md)
+- [compiler_barriers](compiler-barriers.md)
 - [compiler_builtins](compiler-builtins.md)
 - [compiler_builtins_lib](compiler-builtins-lib.md)
 - [concat_idents](concat-idents.md)
 - [link_llvm_intrinsics](link-llvm-intrinsics.md)
 - [linkage](linkage.md)
 - [linked_list_extras](linked-list-extras.md)
+- [linker_flavor](linker-flavor.md)
 - [log_syntax](log-syntax.md)
 - [lookup_host](lookup-host.md)
 - [loop_break_value](loop-break-value.md)
 - [macro_reexport](macro-reexport.md)
 - [main](main.md)
+- [manually_drop](manually-drop.md)
 - [map_entry_recover_keys](map-entry-recover-keys.md)
 - [mpsc_select](mpsc-select.md)
 - [n16](n16.md)
 - [str_checked_slicing](str-checked-slicing.md)
 - [str_escape](str-escape.md)
 - [str_internals](str-internals.md)
+- [str_mut_extras](str-mut-extras.md)
 - [struct_field_attributes](struct-field-attributes.md)
 - [structural_match](structural-match.md)
 - [target_feature](target-feature.md)
diff --git a/src/doc/unstable-book/src/as-c-str.md b/src/doc/unstable-book/src/as-c-str.md
new file mode 100644 (file)
index 0000000..ed32eed
--- /dev/null
@@ -0,0 +1,8 @@
+# `as_c_str`
+
+The tracking issue for this feature is: [#40380]
+
+[#40380]: https://github.com/rust-lang/rust/issues/40380
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md
new file mode 100644 (file)
index 0000000..827447f
--- /dev/null
@@ -0,0 +1,106 @@
+# `compiler_barriers`
+
+The tracking issue for this feature is: [#41091]
+
+[#41091]: https://github.com/rust-lang/rust/issues/41091
+
+------------------------
+
+The `compiler_barriers` feature exposes the `compiler_barrier` function
+in `std::sync::atomic`. This function is conceptually similar to C++'s
+`atomic_signal_fence`, which can currently only be accessed in nightly
+Rust using the `atomic_singlethreadfence_*` instrinsic functions in
+`core`, or through the mostly equivalent literal assembly:
+
+```rust
+#![feature(asm)]
+unsafe { asm!("" ::: "memory" : "volatile") };
+```
+
+A `compiler_barrier` restricts the kinds of memory re-ordering the
+compiler is allowed to do. Specifically, depending on the given ordering
+semantics, the compiler may be disallowed from moving reads or writes
+from before or after the call to the other side of the call to
+`compiler_barrier`. Note that it does **not** prevent the *hardware*
+from doing such re-ordering. This is not a problem in a single-threaded,
+execution context, but when other threads may modify memory at the same
+time, stronger synchronization primitives are required.
+
+## Examples
+
+`compiler_barrier` is generally only useful for preventing a thread from
+racing *with itself*. That is, if a given thread is executing one piece
+of code, and is then interrupted, and starts executing code elsewhere
+(while still in the same thread, and conceptually still on the same
+core). In traditional programs, this can only occur when a signal
+handler is registered. In more low-level code, such situations can also
+arise when handling interrupts, when implementing green threads with
+pre-emption, etc.
+
+To give a straightforward example of when a `compiler_barrier` is
+necessary, consider the following example:
+
+```rust
+# use std::sync::atomic::{AtomicBool, AtomicUsize};
+# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
+# use std::sync::atomic::Ordering;
+static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT;
+static IS_READY: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+    IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
+    IS_READY.store(true, Ordering::Relaxed);
+}
+
+fn signal_handler() {
+    if IS_READY.load(Ordering::Relaxed) {
+        assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
+    }
+}
+```
+
+The way it is currently written, the `assert_eq!` is *not* guaranteed to
+succeed, despite everything happening in a single thread. To see why,
+remember that the compiler is free to swap the stores to
+`IMPORTANT_VARIABLE` and `IS_READ` since they are both
+`Ordering::Relaxed`. If it does, and the signal handler is invoked right
+after `IS_READY` is updated, then the signal handler will see
+`IS_READY=1`, but `IMPORTANT_VARIABLE=0`.
+
+Using a `compiler_barrier`, we can remedy this situation:
+
+```rust
+#![feature(compiler_barriers)]
+# use std::sync::atomic::{AtomicBool, AtomicUsize};
+# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
+# use std::sync::atomic::Ordering;
+use std::sync::atomic::compiler_barrier;
+
+static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT;
+static IS_READY: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+    IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
+    // prevent earlier writes from being moved beyond this point
+    compiler_barrier(Ordering::Release);
+    IS_READY.store(true, Ordering::Relaxed);
+}
+
+fn signal_handler() {
+    if IS_READY.load(Ordering::Relaxed) {
+        assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
+    }
+}
+```
+
+A deeper discussion of compiler barriers with various re-ordering
+semantics (such as `Ordering::SeqCst`) is beyond the scope of this text.
+Curious readers are encouraged to read the Linux kernel's discussion of
+[memory barriers][1], the C++ references on [`std::memory_order`][2] and
+[`atomic_signal_fence`][3], and [this StackOverflow answer][4] for
+further details.
+
+[1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt
+[2]: http://en.cppreference.com/w/cpp/atomic/memory_order
+[3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/
+[4]: http://stackoverflow.com/a/18454971/472927
diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/linker-flavor.md
new file mode 100644 (file)
index 0000000..3965960
--- /dev/null
@@ -0,0 +1,61 @@
+# `linker-flavor`
+
+The tracking issue for this feature is: None
+
+------------------------
+
+Every `rustc` target defaults to some linker. For example, Linux targets default
+to gcc. In some cases, you may want to override the default; you can do that
+with the unstable CLI argument: `-Z linker-flavor`.
+
+Here how you would use this flag to link a Rust binary for the
+`thumbv7m-none-eabi` using LLD instead of GCC.
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi -- \
+    -C linker=ld.lld \
+    -Z linker-flavor=ld \
+    -Z print-link-args | tr ' ' '\n'
+"ld.lld"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o"
+"-o"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c"
+"--gc-sections"
+"-L"
+"$PWD/target/thumbv7m-none-eabi/debug/deps"
+"-L"
+"$PWD/target/debug/deps"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"-Bstatic"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
+"-Bdynamic"
+```
+
+Whereas the default is:
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi -- \
+    -C link-arg=-nostartfiles \
+    -Z print-link-args | tr ' ' '\n'
+"arm-none-eabi-gcc"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o"
+"-o"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9"
+"-Wl,--gc-sections"
+"-nodefaultlibs"
+"-L"
+"$PWD/target/thumbv7m-none-eabi/debug/deps"
+"-L"
+"$PWD/target/debug/deps"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"-Wl,-Bstatic"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
+"-nostartfiles"
+"-Wl,-Bdynamic"
+```
diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/manually-drop.md
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/doc/unstable-book/src/str-mut-extras.md b/src/doc/unstable-book/src/str-mut-extras.md
new file mode 100644 (file)
index 0000000..df4f358
--- /dev/null
@@ -0,0 +1,8 @@
+# `str_mut_extras`
+
+The tracking issue for this feature is: [#str_mut_extras]
+
+[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119
+
+------------------------
+
index ae040a23906595683cc072cf30d7021209349a27..f3a0eebe6984d2a11ca73d93871b6c4314683c15 100644 (file)
@@ -129,7 +129,7 @@ fn main() {
         // should be good to go!
         cmd.arg("--with-jemalloc-prefix=je_");
         cmd.arg("--disable-tls");
-    } else if target.contains("dragonfly") {
+    } else if target.contains("dragonfly") || target.contains("musl") {
         cmd.arg("--with-jemalloc-prefix=je_");
     }
 
index a7a67ef76d4f75599be5998d701b67340ea34d07..83cc1ef09c29c2fdf93e1085a1dda309ec7879dd 100644 (file)
@@ -35,23 +35,23 @@ mod imp {
     // request it as unprefixing cause segfaults (mismatches in allocators).
     extern "C" {
         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                       target_os = "dragonfly", target_os = "windows"),
+                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                    link_name = "je_mallocx")]
         fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                       target_os = "dragonfly", target_os = "windows"),
+                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                    link_name = "je_rallocx")]
         fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                       target_os = "dragonfly", target_os = "windows"),
+                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                    link_name = "je_xallocx")]
         fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                       target_os = "dragonfly", target_os = "windows"),
+                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                    link_name = "je_sdallocx")]
         fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                       target_os = "dragonfly", target_os = "windows"),
+                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                    link_name = "je_nallocx")]
         fn nallocx(size: size_t, flags: c_int) -> size_t;
     }
index dcacef4f0f0d5f301cb189c1647693659e2fc393..b30700c3f694e58482f7ba308509e8548051f772 100644 (file)
@@ -262,7 +262,7 @@ fn replace(&mut self, key: K) -> Option<K> {
     }
 }
 
-/// An iterator over a BTreeMap's entries.
+/// An iterator over a `BTreeMap`'s entries.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     range: Range<'a, K, V>,
@@ -276,7 +276,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A mutable iterator over a BTreeMap's entries.
+/// A mutable iterator over a `BTreeMap`'s entries.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IterMut<'a, K: 'a, V: 'a> {
@@ -284,7 +284,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
     length: usize,
 }
 
-/// An owning iterator over a BTreeMap's entries.
+/// An owning iterator over a `BTreeMap`'s entries.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
     front: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
@@ -303,7 +303,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// An iterator over a BTreeMap's keys.
+/// An iterator over a `BTreeMap`'s keys.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -316,7 +316,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// An iterator over a BTreeMap's values.
+/// An iterator over a `BTreeMap`'s values.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -329,14 +329,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A mutable iterator over a BTreeMap's values.
+/// A mutable iterator over a `BTreeMap`'s values.
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 #[derive(Debug)]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
-/// An iterator over a sub-range of BTreeMap's entries.
+/// An iterator over a sub-range of `BTreeMap`'s entries.
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, K: 'a, V: 'a> {
     front: Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
@@ -350,7 +350,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A mutable iterator over a sub-range of BTreeMap's entries.
+/// A mutable iterator over a sub-range of `BTreeMap`'s entries.
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct RangeMut<'a, K: 'a, V: 'a> {
     front: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
@@ -378,12 +378,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// [`entry`]: struct.BTreeMap.html#method.entry
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Entry<'a, K: 'a, V: 'a> {
-    /// A vacant Entry
+    /// A vacant `Entry`
     #[stable(feature = "rust1", since = "1.0.0")]
     Vacant(#[stable(feature = "rust1", since = "1.0.0")]
            VacantEntry<'a, K, V>),
 
-    /// An occupied Entry
+    /// An occupied `Entry`
     #[stable(feature = "rust1", since = "1.0.0")]
     Occupied(#[stable(feature = "rust1", since = "1.0.0")]
              OccupiedEntry<'a, K, V>),
@@ -403,7 +403,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A vacant Entry. It is part of the [`Entry`] enum.
+/// A vacant `Entry`. It is part of the [`Entry`] enum.
 ///
 /// [`Entry`]: enum.Entry.html
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -425,7 +425,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// An occupied Entry. It is part of the [`Entry`] enum.
+/// An occupied `Entry`. It is part of the [`Entry`] enum.
 ///
 /// [`Entry`]: enum.Entry.html
 #[stable(feature = "rust1", since = "1.0.0")]
index e56b94b2e1ea296d7c8531a647f2959b2c553bc9..ebee75d1a1a6451a99b9cac7a306f018bbff81f0 100644 (file)
@@ -215,7 +215,7 @@ fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
     }
 }
 
-/// An iterator over an EnumSet
+/// An iterator over an `EnumSet`
 pub struct Iter<E> {
     index: usize,
     bits: usize,
index 248c15e96f8f65f3b432fbe7db9dc7645823c1d5..99afd08e81183eb451df419c93a633b43456bb9c 100644 (file)
@@ -10,8 +10,8 @@
 
 //! Collection types.
 //!
-//! See [std::collections](../std/collections/index.html) for a detailed discussion of
-//! collections in Rust.
+//! See [`std::collections`](../std/collections/index.html) for a detailed
+//! discussion of collections in Rust.
 
 #![crate_name = "collections"]
 #![crate_type = "rlib"]
@@ -44,6 +44,7 @@
 #![feature(heap_api)]
 #![feature(inclusive_range)]
 #![feature(lang_items)]
+#![feature(manually_drop)]
 #![feature(nonzero)]
 #![feature(pattern)]
 #![feature(placement_in)]
@@ -57,6 +58,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(str_internals)]
+#![feature(str_mut_extras)]
 #![feature(trusted_len)]
 #![feature(unicode)]
 #![feature(unique)]
index 06d89a6a70b4a8a845051c9116bf9952a04fd171..8f3209d015b159ad955f6a31ee7eac0109bd45b6 100644 (file)
@@ -17,7 +17,7 @@
 use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive};
 use Bound::{self, Excluded, Included, Unbounded};
 
-/// **RangeArgument** is implemented by Rust's built-in range types, produced
+/// `RangeArgument` is implemented by Rust's built-in range types, produced
 /// by range syntax like `..`, `a..`, `..b` or `c..d`.
 pub trait RangeArgument<T: ?Sized> {
     /// Start index bound.
index 6cff315a6ccd9eb28083d2b1f5b2afa9e8dc2430..3069adb12e92cd127c5bd29d03d266da23d49df4 100644 (file)
@@ -1558,7 +1558,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             //    performance than with the 2nd method.
             //
             // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
-            let mut tmp = NoDrop { value: ptr::read(&v[0]) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
 
             // Intermediate state of the insertion process is always tracked by `hole`, which
             // serves two purposes:
@@ -1571,13 +1571,13 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
             // initially held exactly once.
             let mut hole = InsertionHole {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: &mut v[1],
             };
             ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
 
             for i in 2..v.len() {
-                if !is_less(&v[i], &tmp.value) {
+                if !is_less(&v[i], &*tmp) {
                     break;
                 }
                 ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
@@ -1587,12 +1587,6 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
         }
     }
 
-    // Holds a value, but never drops it.
-    #[allow(unions_with_drop_fields)]
-    union NoDrop<T> {
-        value: T
-    }
-
     // When dropped, copies from `src` into `dest`.
     struct InsertionHole<T> {
         src: *mut T,
index c37a4fa6b5572757681971170e2984577d7d3385..d04f414250ade9ee8a70f00a6e571fda980b481d 100644 (file)
@@ -72,7 +72,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::str::{from_utf8_unchecked, ParseBoolError};
+pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use std_unicode::str::SplitWhitespace;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -294,6 +294,13 @@ pub fn as_bytes(&self) -> &[u8] {
         core_str::StrExt::as_bytes(self)
     }
 
+    /// Converts a mutable string slice to a mutable byte slice.
+    #[unstable(feature = "str_mut_extras", issue = "41119")]
+    #[inline(always)]
+    pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+        core_str::StrExt::as_bytes_mut(self)
+    }
+
     /// Converts a string slice to a raw pointer.
     ///
     /// As string slices are a slice of bytes, the raw pointer points to a
index 0ee4c8b8e95a60bec3e8d06cea73460f03bcb274..7d9d7276201bd1ed3f85c5ef2e22b3470a5fb377 100644 (file)
@@ -1790,7 +1790,7 @@ fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
 impl ops::IndexMut<ops::RangeFull> for String {
     #[inline]
     fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
-        unsafe { mem::transmute(&mut *self.vec) }
+        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
@@ -1822,7 +1822,7 @@ fn deref(&self) -> &str {
 impl ops::DerefMut for String {
     #[inline]
     fn deref_mut(&mut self) -> &mut str {
-        unsafe { mem::transmute(&mut *self.vec) }
+        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
     }
 }
 
index 22f2ff1a3461830b13fd9ff25cdb579bd9c1c429..f1ea0010e98c2c2248cafae732884fce2b3d7bec 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! VecDeque is a double-ended queue, which is implemented with the help of a
+//! `VecDeque` is a double-ended queue, which is implemented with the help of a
 //! growing ring buffer.
 //!
 //! This queue has `O(1)` amortized inserts and removals from both ends of the
@@ -1847,7 +1847,7 @@ fn wrap_index(index: usize, size: usize) -> usize {
     index & (size - 1)
 }
 
-/// Returns the two slices that cover the VecDeque's valid range
+/// Returns the two slices that cover the `VecDeque`'s valid range
 trait RingSlices: Sized {
     fn slice(self, from: usize, to: usize) -> Self;
     fn split_at(self, i: usize) -> (Self, Self);
@@ -2047,7 +2047,7 @@ fn is_empty(&self) -> bool {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
-/// A by-value VecDeque iterator
+/// A by-value `VecDeque` iterator
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<T> {
@@ -2097,7 +2097,7 @@ fn is_empty(&self) -> bool {
 #[unstable(feature = "fused", issue = "35602")]
 impl<T> FusedIterator for IntoIter<T> {}
 
-/// A draining VecDeque iterator
+/// A draining `VecDeque` iterator
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, T: 'a> {
     after_tail: usize,
index b27c801cf89d5d26f3d74ba331a3b0e497e5ddc5..98268e3813fac1897e8d7dd66bff9903ecf8dc2d 100644 (file)
@@ -19,6 +19,7 @@
 use convert::TryFrom;
 use fmt::{self, Write};
 use slice;
+use str::from_utf8_unchecked_mut;
 use iter::FusedIterator;
 use mem::transmute;
 
@@ -448,7 +449,7 @@ fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
                     code,
                     dst.len())
             };
-            transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
+            from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
         }
     }
 
index 74ded948b18e74a8dad5126880f24bea19585372..d4544dadaeb0c6af0d70693baa787223a25e6859 100644 (file)
 /// ```
 #[lang = "eq"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
 pub trait PartialEq<Rhs: ?Sized = Self> {
     /// This method tests for `self` and `other` values to be equal, and is used
     /// by `==`.
@@ -550,6 +551,7 @@ fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
 /// ```
 #[lang = "ord"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     /// This method returns an ordering between `self` and `other` values if one exists.
     ///
index 0bfab92fa5d5180270491af1fb3e8320b9587da0..8c3d3ce7d886b085c7b7964e726176475bdfbfff 100644 (file)
@@ -49,8 +49,31 @@ pub mod rt {
     pub mod v1;
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
 /// The type returned by formatter methods.
+///
+/// # Examples
+///
+/// ```
+/// use std::fmt;
+///
+/// #[derive(Debug)]
+/// struct Triangle {
+///     a: f32,
+///     b: f32,
+///     c: f32
+/// }
+///
+/// impl fmt::Display for Triangle {
+///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+///         write!(f, "({}, {}, {})", self.a, self.b, self.c)
+///     }
+/// }
+///
+/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
+///
+/// println!("{}", pythagorean_triple);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
 pub type Result = result::Result<(), Error>;
 
 /// The error type which is returned from formatting a message into a stream.
index e0a4707ff665f58c0bdedbb8fed6f6e29bc897be..b0287631585125a9febd3fb903e5d51e2358ae8e 100644 (file)
     /// initialize memory previous set to the result of `uninit`.
     pub fn uninit<T>() -> T;
 
-    /// Moves a value out of scope without running drop glue.
-    pub fn forget<T>(_: T) -> ();
-
     /// Reinterprets the bits of a value of one type as another type.
     ///
     /// Both types must have the same size. Neither the original, nor the result,
index f5cf3724d0711d8183e685a02d08878f37ad3e95..7be927b28ed7eb7ecfef5fcc8da2ab1d0cdc9410 100644 (file)
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn forget<T>(t: T) {
-    unsafe { intrinsics::forget(t) }
+    ManuallyDrop::new(t);
 }
 
 /// Returns the size of a type in bytes.
@@ -736,3 +736,121 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     }
 }
 
+
+/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
+///
+/// This wrapper is 0-cost.
+///
+/// # Examples
+///
+/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
+/// the type:
+///
+/// ```rust
+/// # #![feature(manually_drop)]
+/// use std::mem::ManuallyDrop;
+/// struct Peach;
+/// struct Banana;
+/// struct Melon;
+/// struct FruitBox {
+///     // Immediately clear there’s something non-trivial going on with these fields.
+///     peach: ManuallyDrop<Peach>,
+///     melon: Melon, // Field that’s independent of the other two.
+///     banana: ManuallyDrop<Banana>,
+/// }
+///
+/// impl Drop for FruitBox {
+///     fn drop(&mut self) {
+///         unsafe {
+///             // Explicit ordering in which field destructors are run specified in the intuitive
+///             // location â€“ the destructor of the structure containing the fields.
+///             // Moreover, one can now reorder fields within the struct however much they want.
+///             ManuallyDrop::drop(&mut self.peach);
+///             ManuallyDrop::drop(&mut self.banana);
+///         }
+///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
+///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
+///     }
+/// }
+/// ```
+#[unstable(feature = "manually_drop", issue = "40673")]
+#[allow(unions_with_drop_fields)]
+pub union ManuallyDrop<T>{ value: T }
+
+impl<T> ManuallyDrop<T> {
+    /// Wrap a value to be manually dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # #![feature(manually_drop)]
+    /// use std::mem::ManuallyDrop;
+    /// ManuallyDrop::new(Box::new(()));
+    /// ```
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub fn new(value: T) -> ManuallyDrop<T> {
+        ManuallyDrop { value: value }
+    }
+
+    /// Extract the value from the ManuallyDrop container.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # #![feature(manually_drop)]
+    /// use std::mem::ManuallyDrop;
+    /// let x = ManuallyDrop::new(Box::new(()));
+    /// let _: Box<()> = ManuallyDrop::into_inner(x);
+    /// ```
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub fn into_inner(slot: ManuallyDrop<T>) -> T {
+        unsafe {
+            slot.value
+        }
+    }
+
+    /// Manually drops the contained value.
+    ///
+    /// # Unsafety
+    ///
+    /// This function runs the destructor of the contained value and thus the wrapped value
+    /// now represents uninitialized data. It is up to the user of this method to ensure the
+    /// uninitialized data is not actually used.
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
+        ptr::drop_in_place(&mut slot.value)
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::Deref for ManuallyDrop<T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            &self.value
+        }
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::DerefMut for ManuallyDrop<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe {
+            &mut self.value
+        }
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
+    fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
+        unsafe {
+            fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
+        }
+    }
+}
index d203b68c0dfd57fd1e8461968bf607a9089de01c..175b3a5a69ac15c86c51109154a6cdf3ef9ffac9 100644 (file)
@@ -242,6 +242,7 @@ pub trait Drop {
 /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
 #[lang = "add"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
 pub trait Add<RHS=Self> {
     /// The resulting type after applying the `+` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -315,6 +316,7 @@ fn add(self, other: $t) -> $t { self + other }
 /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
 #[lang = "sub"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
 pub trait Sub<RHS=Self> {
     /// The resulting type after applying the `-` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -437,6 +439,7 @@ fn sub(self, other: $t) -> $t { self - other }
 /// ```
 #[lang = "mul"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
 pub trait Mul<RHS=Self> {
     /// The resulting type after applying the `*` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -565,6 +568,7 @@ fn mul(self, other: $t) -> $t { self * other }
 /// ```
 #[lang = "div"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
 pub trait Div<RHS=Self> {
     /// The resulting type after applying the `/` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -644,6 +648,7 @@ fn div(self, other: $t) -> $t { self / other }
 /// ```
 #[lang = "rem"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
 pub trait Rem<RHS=Self> {
     /// The resulting type after applying the `%` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -883,6 +888,7 @@ fn not(self) -> $t { !self }
 /// ```
 #[lang = "bitand"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
 pub trait BitAnd<RHS=Self> {
     /// The resulting type after applying the `&` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -966,6 +972,7 @@ fn bitand(self, rhs: $t) -> $t { self & rhs }
 /// ```
 #[lang = "bitor"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
 pub trait BitOr<RHS=Self> {
     /// The resulting type after applying the `|` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1052,6 +1059,7 @@ fn bitor(self, rhs: $t) -> $t { self | rhs }
 /// ```
 #[lang = "bitxor"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
 pub trait BitXor<RHS=Self> {
     /// The resulting type after applying the `^` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1134,6 +1142,7 @@ fn bitxor(self, other: $t) -> $t { self ^ other }
 /// ```
 #[lang = "shl"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
 pub trait Shl<RHS> {
     /// The resulting type after applying the `<<` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1237,6 +1246,7 @@ macro_rules! shl_impl_all {
 /// ```
 #[lang = "shr"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
 pub trait Shr<RHS> {
     /// The resulting type after applying the `>>` operator
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1321,6 +1331,7 @@ macro_rules! shr_impl_all {
 /// ```
 #[lang = "add_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
 pub trait AddAssign<Rhs=Self> {
     /// The method for the `+=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1377,6 +1388,7 @@ fn add_assign(&mut self, other: $t) { *self += other }
 /// ```
 #[lang = "sub_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
 pub trait SubAssign<Rhs=Self> {
     /// The method for the `-=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1422,6 +1434,7 @@ fn sub_assign(&mut self, other: $t) { *self -= other }
 /// ```
 #[lang = "mul_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
 pub trait MulAssign<Rhs=Self> {
     /// The method for the `*=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1467,6 +1480,7 @@ fn mul_assign(&mut self, other: $t) { *self *= other }
 /// ```
 #[lang = "div_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
 pub trait DivAssign<Rhs=Self> {
     /// The method for the `/=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1511,6 +1525,7 @@ fn div_assign(&mut self, other: $t) { *self /= other }
 /// ```
 #[lang = "rem_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
 pub trait RemAssign<Rhs=Self> {
     /// The method for the `%=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1597,6 +1612,7 @@ fn rem_assign(&mut self, other: $t) { *self %= other }
 /// ```
 #[lang = "bitand_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
 pub trait BitAndAssign<Rhs=Self> {
     /// The method for the `&=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1641,6 +1657,7 @@ fn bitand_assign(&mut self, other: $t) { *self &= other }
 /// ```
 #[lang = "bitor_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
 pub trait BitOrAssign<Rhs=Self> {
     /// The method for the `|=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1685,6 +1702,7 @@ fn bitor_assign(&mut self, other: $t) { *self |= other }
 /// ```
 #[lang = "bitxor_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
 pub trait BitXorAssign<Rhs=Self> {
     /// The method for the `^=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1729,6 +1747,7 @@ fn bitxor_assign(&mut self, other: $t) { *self ^= other }
 /// ```
 #[lang = "shl_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
 pub trait ShlAssign<Rhs> {
     /// The method for the `<<=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1794,6 +1813,7 @@ macro_rules! shl_assign_impl_all {
 /// ```
 #[lang = "shr_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
 pub trait ShrAssign<Rhs=Self> {
     /// The method for the `>>=` operator
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
index 6d598677c9ba4f0cad90dc5bf1458d1d94433f58..87dfdfe57b65c77db0443d99ea6e7d46143c5089 100644 (file)
@@ -1190,6 +1190,19 @@ fn next_back(&mut self) -> Option<$elem> {
                     }
                 }
             }
+
+            fn rfind<F>(&mut self, mut predicate: F) -> Option<Self::Item>
+                where F: FnMut(&Self::Item) -> bool,
+            {
+                self.rsearch_while(None, move |elt| {
+                    if predicate(&elt) {
+                        SearchWhile::Done(Some(elt))
+                    } else {
+                        SearchWhile::Continue
+                    }
+                })
+            }
+
         }
 
         // search_while is a generalization of the internal iteration methods.
index 7065fdb79fc4040a6ca225634408141e1871a830..6f9f2915dfe102c1fe6022d660816e69279152ed 100644 (file)
 use mem;
 use ptr;
 
-/// Holds a value, but never drops it.
-#[allow(unions_with_drop_fields)]
-union NoDrop<T> {
-    value: T
-}
-
 /// When dropped, copies from `src` into `dest`.
 struct CopyOnDrop<T> {
     src: *mut T,
@@ -49,15 +43,15 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
             // Read the first element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
             let mut hole = CopyOnDrop {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: v.get_unchecked_mut(1),
             };
             ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1);
 
             for i in 2..len {
-                if !is_less(v.get_unchecked(i), &tmp.value) {
+                if !is_less(v.get_unchecked(i), &*tmp) {
                     break;
                 }
 
@@ -81,15 +75,15 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
             // Read the last element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
             let mut hole = CopyOnDrop {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: v.get_unchecked_mut(len - 2),
             };
             ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1);
 
             for i in (0..len-2).rev() {
-                if !is_less(&tmp.value, v.get_unchecked(i)) {
+                if !is_less(&*tmp, v.get_unchecked(i)) {
                     break;
                 }
 
@@ -403,12 +397,12 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
 
         // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
         // operation panics, the pivot will be automatically written back into the slice.
-        let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+        let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
         let _pivot_guard = CopyOnDrop {
-            src: unsafe { &mut tmp.value },
+            src: &mut *tmp,
             dest: pivot,
         };
-        let pivot = unsafe { &tmp.value };
+        let pivot = &*tmp;
 
         // Find the first pair of out-of-order elements.
         let mut l = 0;
@@ -452,12 +446,12 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
 
     // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
     // operation panics, the pivot will be automatically written back into the slice.
-    let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+    let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
     let _pivot_guard = CopyOnDrop {
-        src: unsafe { &mut tmp.value },
+        src: &mut *tmp,
         dest: pivot,
     };
-    let pivot = unsafe { &tmp.value };
+    let pivot = &*tmp;
 
     // Now partition the slice.
     let mut l = 0;
index 352cc926994e3685ae5ca5554eba5f9fbfd3e3c6..2ceef54ffed6a6ddd37535419ca26ab4043e6ab1 100644 (file)
@@ -21,8 +21,8 @@
 use convert::TryFrom;
 use fmt;
 use iter::{Map, Cloned, FusedIterator};
-use mem;
 use slice::{self, SliceIndex};
+use mem;
 
 pub mod pattern;
 
@@ -300,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
     Ok(unsafe { from_utf8_unchecked(v) })
 }
 
+/// Converts a mutable slice of bytes to a mutable string slice.
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
+    run_utf8_validation(v)?;
+    Ok(unsafe { from_utf8_unchecked_mut(v) })
+}
+
 /// Forms a str from a pointer and a length.
 ///
 /// The `len` argument is the number of bytes in the string.
@@ -325,7 +332,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 /// str is returned.
 ///
 unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str {
-    mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len))
+    from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len))
 }
 
 /// Converts a slice of bytes to a string slice without checking
@@ -365,6 +372,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
     mem::transmute(v)
 }
 
+/// Converts a slice of bytes to a string slice without checking
+/// that the string contains valid UTF-8; mutable version.
+///
+/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
+///
+/// [fromutf8]: fn.from_utf8_unchecked.html
+#[inline(always)]
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
+    mem::transmute(v)
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Utf8Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1474,7 +1493,6 @@ pub fn utf8_char_width(b: u8) -> usize {
 mod traits {
     use cmp::Ordering;
     use ops;
-    use mem;
     use slice::{self, SliceIndex};
     use str::eq_slice;
 
@@ -1811,7 +1829,7 @@ unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr().offset(self.start as isize);
             let len = self.end - self.start;
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1859,7 +1877,7 @@ unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
         #[inline]
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr();
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1905,7 +1923,7 @@ unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr().offset(self.start as isize);
             let len = slice.len() - self.start;
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1998,7 +2016,7 @@ unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
         #[inline]
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr();
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2096,6 +2114,8 @@ fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
     fn is_char_boundary(&self, index: usize) -> bool;
     #[stable(feature = "core", since = "1.6.0")]
     fn as_bytes(&self) -> &[u8];
+    #[unstable(feature = "str_mut_extras", issue = "0")]
+    unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
     #[stable(feature = "core", since = "1.6.0")]
     fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
     #[stable(feature = "core", since = "1.6.0")]
@@ -2373,6 +2393,11 @@ fn as_bytes(&self) -> &[u8] {
         unsafe { mem::transmute(self) }
     }
 
+    #[inline]
+    unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+        mem::transmute(self)
+    }
+
     fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
         pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
index a4050f271eb99b30a08eb91961680bf468444e28..0c70524ead246beee3a85bbe16754f9612f34329 100644 (file)
@@ -1591,6 +1591,47 @@ pub fn fence(order: Ordering) {
 }
 
 
+/// A compiler memory barrier.
+///
+/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering
+/// memory operations across this point. Which reorderings are disallowed is dictated by the given
+/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory
+/// synchronization; for that, a [`fence`] is needed.
+///
+/// The re-ordering prevented by the different ordering semantics are:
+///
+///  - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed.
+///  - with [`Release`], preceding reads and writes cannot be moved past subsequent writes.
+///  - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads.
+///  - with [`AcqRel`], both of the above rules are enforced.
+///
+/// # Panics
+///
+/// Panics if `order` is [`Relaxed`].
+///
+/// [`fence`]: fn.fence.html
+/// [`Ordering`]: enum.Ordering.html
+/// [`Acquire`]: enum.Ordering.html#variant.Acquire
+/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst
+/// [`Release`]: enum.Ordering.html#variant.Release
+/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
+/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
+#[inline]
+#[unstable(feature = "compiler_barriers", issue = "41091")]
+pub fn compiler_barrier(order: Ordering) {
+    unsafe {
+        match order {
+            Acquire => intrinsics::atomic_singlethreadfence_acq(),
+            Release => intrinsics::atomic_singlethreadfence_rel(),
+            AcqRel => intrinsics::atomic_singlethreadfence_acqrel(),
+            SeqCst => intrinsics::atomic_singlethreadfence(),
+            Relaxed => panic!("there is no such thing as a relaxed barrier"),
+            __Nonexhaustive => panic!("invalid memory ordering"),
+        }
+    }
+}
+
+
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "atomic_debug", since = "1.3.0")]
 impl fmt::Debug for AtomicBool {
index d92c378160d2e0e4ba3eabcc5fcdc813675b07c4..528ab3bc84523e184ee7b41b12bbce7d9e36ee57 100644 (file)
@@ -20,6 +20,7 @@
 #![feature(fixed_size_array)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
+#![feature(iter_rfind)]
 #![feature(libc)]
 #![feature(nonzero)]
 #![feature(rand)]
index ec38345030fa5897423ff55d2f4f882dcff4c1ee..15047204e50d609699e5df8bcee730d9aa37ee6c 100644 (file)
@@ -225,6 +225,19 @@ fn get_unchecked_mut_range() {
     }
 }
 
+#[test]
+fn test_find_rfind() {
+    let v = [0, 1, 2, 3, 4, 5];
+    let mut iter = v.iter();
+    let mut i = v.len();
+    while let Some(&elt) = iter.rfind(|_| true) {
+        i -= 1;
+        assert_eq!(elt, v[i]);
+    }
+    assert_eq!(i, 0);
+    assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3));
+}
+
 #[test]
 fn sort_unstable() {
     let mut v = [0; 600];
index c9722adc9510cc6f7eaa8f6a37e9295c4d983931..8dc298b9c2a1788b1c0fcf0c4e1179c712b820ed 100644 (file)
@@ -89,7 +89,7 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
             let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
             match (&from.sty, sk_to) {
                 (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
-                        if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
+                        if size_to == Pointer.size(self.infcx) => {
                     struct_span_err!(self.infcx.tcx.sess, span, E0591,
                                      "`{}` is zero-sized and can't be transmuted to `{}`",
                                      from, to)
index a0603c5795247c75fb98911daae1c1b3c7ddd284..b9a974045bced110527e953ebffe296dccceb6b6 100644 (file)
@@ -19,7 +19,7 @@
 use session::{early_error, early_warn, Session};
 use session::search_paths::SearchPaths;
 
-use rustc_back::PanicStrategy;
+use rustc_back::{LinkerFlavor, PanicStrategy};
 use rustc_back::target::Target;
 use lint;
 use middle::cstore;
@@ -641,12 +641,16 @@ mod $mod_desc {
             Some("either `panic` or `abort`");
         pub const parse_sanitizer: Option<&'static str> =
             Some("one of: `address`, `leak`, `memory` or `thread`");
+        pub const parse_linker_flavor: Option<&'static str> =
+            Some(::rustc_back::LinkerFlavor::one_of());
+        pub const parse_optimization_fuel: Option<&'static str> =
+            Some("crate=integer");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
         use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
-        use rustc_back::PanicStrategy;
+        use rustc_back::{LinkerFlavor, PanicStrategy};
 
         $(
             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
@@ -777,6 +781,29 @@ fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
             }
             true
         }
+
+        fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+            match v.and_then(LinkerFlavor::from_str) {
+                Some(lf) => *slote = Some(lf),
+                _ => return false,
+            }
+            true
+        }
+
+        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+            match v {
+                None => false,
+                Some(s) => {
+                    let parts = s.split('=').collect::<Vec<_>>();
+                    if parts.len() != 2 { return false; }
+                    let crate_name = parts[0].to_string();
+                    let fuel = parts[1].parse::<u64>();
+                    if fuel.is_err() { return false; }
+                    *slot = Some((crate_name, fuel.unwrap()));
+                    true
+                }
+            }
+        }
     }
 ) }
 
@@ -979,6 +1006,12 @@ fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
           "pass `-install_name @rpath/...` to the macOS linker"),
     sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
                                    "Use a sanitizer"),
+    linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
+                                           "Linker flavor"),
+    fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
+        "Set the optimization fuel quota for a crate."),
+    print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
+        "Make Rustc print the total optimization fuel used by a crate."),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1772,11 +1805,13 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
 
     impl_dep_tracking_hash_via_hash!(bool);
     impl_dep_tracking_hash_via_hash!(usize);
+    impl_dep_tracking_hash_via_hash!(u64);
     impl_dep_tracking_hash_via_hash!(String);
     impl_dep_tracking_hash_via_hash!(lint::Level);
     impl_dep_tracking_hash_via_hash!(Option<bool>);
     impl_dep_tracking_hash_via_hash!(Option<usize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
+    impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
@@ -1798,6 +1833,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
                                                  Option<cstore::NativeLibraryKind>));
+    impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
     impl DepTrackingHash for SearchPaths {
         fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
             let mut elems: Vec<_> = self
index 3ba82f34c3266a804fece8554e94707fb562c796..039db3d9ee9117484aa69847768089bbfcdf608b 100644 (file)
@@ -36,7 +36,7 @@
 use syntax::feature_gate::AttributeType;
 use syntax_pos::{Span, MultiSpan};
 
-use rustc_back::PanicStrategy;
+use rustc_back::{LinkerFlavor, PanicStrategy};
 use rustc_back::target::Target;
 use rustc_data_structures::flock;
 use llvm;
@@ -123,6 +123,20 @@ pub struct Session {
     pub code_stats: RefCell<CodeStats>,
 
     next_node_id: Cell<ast::NodeId>,
+
+    /// If -zfuel=crate=n is specified, Some(crate).
+    optimization_fuel_crate: Option<String>,
+    /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
+    optimization_fuel_limit: Cell<u64>,
+    /// We're rejecting all further optimizations.
+    out_of_fuel: Cell<bool>,
+
+    // The next two are public because the driver needs to read them.
+
+    /// If -zprint-fuel=crate, Some(crate).
+    pub print_fuel_crate: Option<String>,
+    /// Always set to zero and incremented so that we can print fuel expended by a crate.
+    pub print_fuel: Cell<u64>,
 }
 
 pub struct PerfStats {
@@ -363,6 +377,9 @@ pub fn lto(&self) -> bool {
     pub fn panic_strategy(&self) -> PanicStrategy {
         self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
     }
+    pub fn linker_flavor(&self) -> LinkerFlavor {
+        self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor)
+    }
     pub fn no_landing_pads(&self) -> bool {
         self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
     }
@@ -504,6 +521,32 @@ pub fn print_perf_stats(&self) {
         println!("Total time spent decoding DefPath tables:      {}",
                  duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
     }
+
+    /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
+    /// This expends fuel if applicable, and records fuel if applicable.
+    pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
+        let mut ret = true;
+        match self.optimization_fuel_crate {
+            Some(ref c) if c == crate_name => {
+                let fuel = self.optimization_fuel_limit.get();
+                ret = fuel != 0;
+                if fuel == 0 && !self.out_of_fuel.get() {
+                    println!("optimization-fuel-exhausted: {}", msg());
+                    self.out_of_fuel.set(true);
+                } else if fuel > 0 {
+                    self.optimization_fuel_limit.set(fuel-1);
+                }
+            }
+            _ => {}
+        }
+        match self.print_fuel_crate {
+            Some(ref c) if c == crate_name=> {
+                self.print_fuel.set(self.print_fuel.get()+1);
+            },
+            _ => {}
+        }
+        ret
+    }
 }
 
 pub fn build_session(sopts: config::Options,
@@ -599,6 +642,12 @@ pub fn build_session_(sopts: config::Options,
         }
     );
 
+    let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
+    let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
+        .map(|i| i.1).unwrap_or(0));
+    let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
+    let print_fuel = Cell::new(0);
+
     let sess = Session {
         dep_graph: dep_graph.clone(),
         target: target_cfg,
@@ -640,6 +689,11 @@ pub fn build_session_(sopts: config::Options,
             decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
         },
         code_stats: RefCell::new(CodeStats::new()),
+        optimization_fuel_crate: optimization_fuel_crate,
+        optimization_fuel_limit: optimization_fuel_limit,
+        print_fuel_crate: print_fuel_crate,
+        print_fuel: print_fuel,
+        out_of_fuel: Cell::new(false),
     };
 
     init_llvm(&sess);
index 152dd6ac3000f71f8b6beb69a5525b64350cd3ff..931c77badad222009ee0e6da53af98e99d2b5ee1 100644 (file)
@@ -524,15 +524,8 @@ pub fn report_selection_error(&self,
                             "the trait bound `{}` is not satisfied{}",
                             trait_ref.to_predicate(),
                             post_message);
-                        err.span_label(span,
-                                        &format!("{}the trait `{}` is not \
-                                                    implemented for `{}`",
-                                                pre_message,
-                                                trait_ref,
-                                                trait_ref.self_ty()));
 
                         // Try to report a help message
-
                         if !trait_ref.has_infer_types() &&
                             self.predicate_can_apply(trait_ref) {
                             // If a where-clause may be useful, remind the
@@ -544,17 +537,21 @@ pub fn report_selection_error(&self,
                             // which is somewhat confusing.
                             err.help(&format!("consider adding a `where {}` bound",
                                                 trait_ref.to_predicate()));
-                        } else if let Some(s) = self.on_unimplemented_note(trait_ref,
-                                                                            obligation) {
+                        } else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) {
                             // If it has a custom "#[rustc_on_unimplemented]"
                             // error message, let's display it!
                             err.note(&s);
                         } else {
-                            // If we can't show anything useful, try to find
-                            // similar impls.
+                            // Can't show anything else useful, try to find similar impls.
                             let impl_candidates = self.find_similar_impl_candidates(trait_ref);
                             self.report_similar_impl_candidates(impl_candidates, &mut err);
                         }
+
+                        err.span_label(span,
+                                       &format!("{}the trait `{}` is not implemented for `{}`",
+                                                pre_message,
+                                                trait_ref,
+                                                trait_ref.self_ty()));
                         err
                     }
 
@@ -997,3 +994,4 @@ fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
                           suggested_limit));
     }
 }
+
index da56514ea82fbf9e485c3f1f761ff9253f9b54cc..8b7438c0bfad2ed5f73efbfece42ffbbd22978d4 100644 (file)
@@ -732,6 +732,11 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        }, f)
     }
+
+    pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
+        let cname = self.crate_name(LOCAL_CRATE).as_str();
+        self.sess.consider_optimizing(&cname, msg)
+    }
 }
 
 impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
index 571ef30b6b9096356a0f92b216088c5d6571d036..d7a4b3fda63bb84054d49fde393e1f2ef62e9fe3 100644 (file)
@@ -25,6 +25,7 @@
 use std::fmt;
 use std::i64;
 use std::iter;
+use std::ops::Deref;
 
 /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
@@ -201,6 +202,16 @@ pub fn ptr_sized_integer(&self) -> Integer {
     }
 }
 
+pub trait HasDataLayout: Copy {
+    fn data_layout(&self) -> &TargetDataLayout;
+}
+
+impl<'a> HasDataLayout for &'a TargetDataLayout {
+    fn data_layout(&self) -> &TargetDataLayout {
+        self
+    }
+}
+
 /// Endianness of the target, which must match cfg(target-endian).
 #[derive(Copy, Clone)]
 pub enum Endian {
@@ -241,7 +252,9 @@ pub fn abi_align(self, align: Align) -> Size {
         Size::from_bytes((self.bytes() + mask) & !mask)
     }
 
-    pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
+    pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
+        let dl = cx.data_layout();
+
         // Each Size is less than dl.obj_size_bound(), so the sum is
         // also less than 1 << 62 (and therefore can't overflow).
         let bytes = self.bytes() + offset.bytes();
@@ -253,7 +266,9 @@ pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
         }
     }
 
-    pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {
+    pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
+        let dl = cx.data_layout();
+
         // Each Size is less than dl.obj_size_bound(), so the sum is
         // also less than 1 << 62 (and therefore can't overflow).
         match self.bytes().checked_mul(count) {
@@ -353,7 +368,9 @@ pub fn size(&self) -> Size {
         }
     }
 
-    pub fn align(&self, dl: &TargetDataLayout)-> Align {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match *self {
             I1 => dl.i1_align,
             I8 => dl.i8_align,
@@ -407,7 +424,9 @@ pub fn fit_unsigned(x: u64) -> Integer {
     }
 
     /// Find the smallest integer with the given alignment.
-    pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option<Integer> {
+    pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> {
+        let dl = cx.data_layout();
+
         let wanted = align.abi();
         for &candidate in &[I8, I16, I32, I64] {
             let ty = Int(candidate);
@@ -419,7 +438,9 @@ pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option<Integer> {
     }
 
     /// Get the Integer type from an attr::IntType.
-    pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {
+    pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
+        let dl = cx.data_layout();
+
         match ity {
             attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
             attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
@@ -449,7 +470,7 @@ fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
         let min_default = I8;
 
         if let Some(ity) = repr.int {
-            let discr = Integer::from_attr(&tcx.data_layout, ity);
+            let discr = Integer::from_attr(tcx, ity);
             let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
             if discr < fit {
                 bug!("Integer::repr_discr: `#[repr]` hint too small for \
@@ -490,7 +511,9 @@ pub enum Primitive {
 }
 
 impl Primitive {
-    pub fn size(self, dl: &TargetDataLayout) -> Size {
+    pub fn size<C: HasDataLayout>(self, cx: C) -> Size {
+        let dl = cx.data_layout();
+
         match self {
             Int(I1) | Int(I8) => Size::from_bits(8),
             Int(I16) => Size::from_bits(16),
@@ -501,7 +524,9 @@ pub fn size(self, dl: &TargetDataLayout) -> Size {
         }
     }
 
-    pub fn align(self, dl: &TargetDataLayout) -> Align {
+    pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match self {
             Int(I1) => dl.i1_align,
             Int(I8) => dl.i8_align,
@@ -555,7 +580,6 @@ enum StructKind {
 }
 
 impl<'a, 'gcx, 'tcx> Struct {
-    // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
     fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
                   repr: &ReprOptions, kind: StructKind,
                   scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
@@ -573,12 +597,8 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
         // Neither do  1-member and 2-member structs.
         // In addition, code in trans assume that 2-element structs can become pairs.
         // It's easier to just short-circuit here.
-        let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
-            && ! (repr.c || repr.packed);
-
-        // Disable field reordering until we can decide what to do.
-        // The odd pattern here avoids a warning about the value never being read.
-        if can_optimize { can_optimize = false; }
+        let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
+            && !(repr.c || repr.packed || repr.linear || repr.simd);
 
         let (optimize, sort_ascending) = match kind {
             StructKind::AlwaysSizedUnivariant => (can_optimize, false),
@@ -681,8 +701,8 @@ pub fn stride(&self) -> Size {
     }
 
     /// Determine whether a structure would be zero-sized, given its fields.
-    pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-                                  -> Result<bool, LayoutError<'gcx>>
+    fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
+                              -> Result<bool, LayoutError<'gcx>>
     where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         for field in fields {
             let field = field?;
@@ -830,7 +850,7 @@ pub struct Union {
 }
 
 impl<'a, 'gcx, 'tcx> Union {
-    pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+    fn new(dl: &TargetDataLayout, packed: bool) -> Union {
         Union {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             min_size: Size::from_bytes(0),
@@ -839,10 +859,10 @@ pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
     }
 
     /// Extend the Struct with more fields.
-    pub fn extend<I>(&mut self, dl: &TargetDataLayout,
-                     fields: I,
-                     scapegoat: Ty<'gcx>)
-                     -> Result<(), LayoutError<'gcx>>
+    fn extend<I>(&mut self, dl: &TargetDataLayout,
+                 fields: I,
+                 scapegoat: Ty<'gcx>)
+                 -> Result<(), LayoutError<'gcx>>
     where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         for (index, field) in fields.enumerate() {
             let field = field?;
@@ -904,7 +924,8 @@ pub enum Layout {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
         align: Align,
-        size: Size
+        element_size: Size,
+        count: u64
     },
 
     /// TyRawPtr or TyRef with a !Sized pointee.
@@ -1087,25 +1108,35 @@ pub fn compute_uncached(ty: Ty<'gcx>,
             // Arrays and slices.
             ty::TyArray(element, count) => {
                 let element = element.layout(infcx)?;
+                let element_size = element.size(dl);
+                // FIXME(eddyb) Don't use host `usize` for array lengths.
+                let usize_count: usize = count;
+                let count = usize_count as u64;
+                if element_size.checked_mul(count, dl).is_none() {
+                    return Err(LayoutError::SizeOverflow(ty));
+                }
                 Array {
                     sized: true,
                     align: element.align(dl),
-                    size: element.size(dl).checked_mul(count as u64, dl)
-                                 .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
+                    element_size: element_size,
+                    count: count
                 }
             }
             ty::TySlice(element) => {
+                let element = element.layout(infcx)?;
                 Array {
                     sized: false,
-                    align: element.layout(infcx)?.align(dl),
-                    size: Size::from_bytes(0)
+                    align: element.align(dl),
+                    element_size: element.size(dl),
+                    count: 0
                 }
             }
             ty::TyStr => {
                 Array {
                     sized: false,
                     align: dl.i8_align,
-                    size: Size::from_bytes(0)
+                    element_size: Size::from_bytes(1),
+                    count: 0
                 }
             }
 
@@ -1440,22 +1471,32 @@ pub fn is_unsized(&self) -> bool {
         }
     }
 
-    pub fn size(&self, dl: &TargetDataLayout) -> Size {
+    pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
+        let dl = cx.data_layout();
+
         match *self {
             Scalar { value, .. } | RawNullablePointer { value, .. } => {
                 value.size(dl)
             }
 
             Vector { element, count } => {
-                let elem_size = element.size(dl);
-                let vec_size = match elem_size.checked_mul(count, dl) {
+                let element_size = element.size(dl);
+                let vec_size = match element_size.checked_mul(count, dl) {
                     Some(size) => size,
                     None => bug!("Layout::size({:?}): {} * {} overflowed",
-                                 self, elem_size.bytes(), count)
+                                 self, element_size.bytes(), count)
                 };
                 vec_size.abi_align(self.align(dl))
             }
 
+            Array { element_size, count, .. } => {
+                match element_size.checked_mul(count, dl) {
+                    Some(size) => size,
+                    None => bug!("Layout::size({:?}): {} * {} overflowed",
+                                 self, element_size.bytes(), count)
+                }
+            }
+
             FatPointer { metadata, .. } => {
                 // Effectively a (ptr, meta) tuple.
                 Pointer.size(dl).abi_align(metadata.align(dl))
@@ -1464,7 +1505,7 @@ pub fn size(&self, dl: &TargetDataLayout) -> Size {
             }
 
             CEnum { discr, .. } => Int(discr).size(dl),
-            Array { size, .. } | General { size, .. } => size,
+            General { size, .. } => size,
             UntaggedUnion { ref variants } => variants.stride(),
 
             Univariant { ref variant, .. } |
@@ -1474,7 +1515,9 @@ pub fn size(&self, dl: &TargetDataLayout) -> Size {
         }
     }
 
-    pub fn align(&self, dl: &TargetDataLayout) -> Align {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        let dl = cx.data_layout();
+
         match *self {
             Scalar { value, .. } | RawNullablePointer { value, .. } => {
                 value.align(dl)
@@ -1513,6 +1556,61 @@ pub fn align(&self, dl: &TargetDataLayout) -> Align {
             }
         }
     }
+
+    pub fn field_offset<C: HasDataLayout>(&self,
+                                          cx: C,
+                                          i: usize,
+                                          variant_index: Option<usize>)
+                                          -> Size {
+        let dl = cx.data_layout();
+
+        match *self {
+            Scalar { .. } |
+            CEnum { .. } |
+            UntaggedUnion { .. } |
+            RawNullablePointer { .. } => {
+                Size::from_bytes(0)
+            }
+
+            Vector { element, count } => {
+                let element_size = element.size(dl);
+                let i = i as u64;
+                assert!(i < count);
+                Size::from_bytes(element_size.bytes() * count)
+            }
+
+            Array { element_size, count, .. } => {
+                let i = i as u64;
+                assert!(i < count);
+                Size::from_bytes(element_size.bytes() * count)
+            }
+
+            FatPointer { metadata, .. } => {
+                // Effectively a (ptr, meta) tuple.
+                assert!(i < 2);
+                if i == 0 {
+                    Size::from_bytes(0)
+                } else {
+                    Pointer.size(dl).abi_align(metadata.align(dl))
+                }
+            }
+
+            Univariant { ref variant, .. } => variant.offsets[i],
+
+            General { ref variants, .. } => {
+                let v = variant_index.expect("variant index required");
+                variants[v].offsets[i + 1]
+            }
+
+            StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
+                if Some(nndiscr as usize) == variant_index {
+                    nonnull.offsets[i]
+                } else {
+                    Size::from_bytes(0)
+                }
+            }
+        }
+    }
 }
 
 /// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1544,7 +1642,7 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
         // First try computing a static layout.
         let err = match ty.layout(infcx) {
             Ok(layout) => {
-                return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout)));
+                return Ok(SizeSkeleton::Known(layout.size(tcx)));
             }
             Err(err) => err
         };
@@ -1658,3 +1756,192 @@ pub fn same_size(self, other: SizeSkeleton) -> bool {
         }
     }
 }
+
+/// A pair of a type and its layout. Implements various
+/// type traversal APIs (e.g. recursing into fields).
+#[derive(Copy, Clone, Debug)]
+pub struct TyLayout<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub layout: &'tcx Layout,
+    pub variant_index: Option<usize>,
+}
+
+impl<'tcx> Deref for TyLayout<'tcx> {
+    type Target = Layout;
+    fn deref(&self) -> &Layout {
+        self.layout
+    }
+}
+
+pub trait HasTyCtxt<'tcx>: HasDataLayout {
+    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.data_layout
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+        self.global_tcx()
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+        self.tcx.global_tcx()
+    }
+}
+
+pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
+    type TyLayout;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+}
+
+impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+    type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
+
+    fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
+        let ty = normalize_associated_type(self, ty);
+
+        Ok(TyLayout {
+            ty: ty,
+            layout: ty.layout(self)?,
+            variant_index: None
+        })
+    }
+}
+
+impl<'a, 'tcx> TyLayout<'tcx> {
+    pub fn for_variant(&self, variant_index: usize) -> Self {
+        TyLayout {
+            variant_index: Some(variant_index),
+            ..*self
+        }
+    }
+
+    pub fn field_offset<C: HasDataLayout>(&self, cx: C, i: usize) -> Size {
+        self.layout.field_offset(cx, i, self.variant_index)
+    }
+
+    pub fn field_count(&self) -> usize {
+        // Handle enum/union through the type rather than Layout.
+        if let ty::TyAdt(def, _) = self.ty.sty {
+            let v = self.variant_index.unwrap_or(0);
+            if def.variants.is_empty() {
+                assert_eq!(v, 0);
+                return 0;
+            } else {
+                return def.variants[v].fields.len();
+            }
+        }
+
+        match *self.layout {
+            Scalar { .. } => {
+                bug!("TyLayout::field_count({:?}): not applicable", self)
+            }
+
+            // Handled above (the TyAdt case).
+            CEnum { .. } |
+            General { .. } |
+            UntaggedUnion { .. } |
+            RawNullablePointer { .. } |
+            StructWrappedNullablePointer { .. } => bug!(),
+
+            FatPointer { .. } => 2,
+
+            Vector { count, .. } |
+            Array { count, .. } => {
+                let usize_count = count as usize;
+                assert_eq!(usize_count as u64, count);
+                usize_count
+            }
+
+            Univariant { ref variant, .. } => variant.offsets.len(),
+        }
+    }
+
+    pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
+        let tcx = cx.tcx();
+
+        let ptr_field_type = |pointee: Ty<'tcx>| {
+            let slice = |element: Ty<'tcx>| {
+                assert!(i < 2);
+                if i == 0 {
+                    tcx.mk_mut_ptr(element)
+                } else {
+                    tcx.types.usize
+                }
+            };
+            match tcx.struct_tail(pointee).sty {
+                ty::TySlice(element) => slice(element),
+                ty::TyStr => slice(tcx.types.u8),
+                ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()),
+                _ => bug!("TyLayout::field_type({:?}): not applicable", self)
+            }
+        };
+
+        match self.ty.sty {
+            ty::TyBool |
+            ty::TyChar |
+            ty::TyInt(_) |
+            ty::TyUint(_) |
+            ty::TyFloat(_) |
+            ty::TyFnPtr(_) |
+            ty::TyNever |
+            ty::TyFnDef(..) |
+            ty::TyDynamic(..) => {
+                bug!("TyLayout::field_type({:?}): not applicable", self)
+            }
+
+            // Potentially-fat pointers.
+            ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
+            ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                ptr_field_type(pointee)
+            }
+            ty::TyAdt(def, _) if def.is_box() => {
+                ptr_field_type(self.ty.boxed_ty())
+            }
+
+            // Arrays and slices.
+            ty::TyArray(element, _) |
+            ty::TySlice(element) => element,
+            ty::TyStr => tcx.types.u8,
+
+            // Tuples and closures.
+            ty::TyClosure(def_id, ref substs) => {
+                substs.upvar_tys(def_id, tcx).nth(i).unwrap()
+            }
+
+            ty::TyTuple(tys, _) => tys[i],
+
+            // SIMD vector types.
+            ty::TyAdt(def, ..) if def.repr.simd => {
+                self.ty.simd_type(tcx)
+            }
+
+            // ADTs.
+            ty::TyAdt(def, substs) => {
+                def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs)
+            }
+
+            ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
+            ty::TyInfer(_) | ty::TyError => {
+                bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
+            }
+        }
+    }
+
+    pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
+        cx.layout_of(self.field_type(cx, i))
+    }
+}
index 292e30e3d41f19403353bfdd2a055ac4c1066daf..a2c356c20db09d563afa0e532dc964c39f139138 100644 (file)
@@ -1411,13 +1411,16 @@ pub struct ReprOptions {
     pub packed: bool,
     pub simd: bool,
     pub int: Option<attr::IntType>,
+    // Internal only for now. If true, don't reorder fields.
+    pub linear: bool,
 }
 
 impl_stable_hash_for!(struct ReprOptions {
     c,
     packed,
     simd,
-    int
+    int,
+    linear
 });
 
 impl ReprOptions {
@@ -1440,6 +1443,9 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
             ret.simd = true;
         }
 
+        // This is here instead of layout because the choice must make it into metadata.
+        ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}",
+            tcx.item_path_str(did)));
         ret
     }
 
index 000e4eb59bf05c7f65981c10f58629c64030896d..6679cc73029c7e119edd15ff81fdb00f36d5c52d 100644 (file)
 
 use serialize::json::{Json, ToJson};
 
+macro_rules! linker_flavor {
+    ($(($variant:ident, $string:expr),)+) => {
+        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
+                 RustcEncodable, RustcDecodable)]
+        pub enum LinkerFlavor {
+            $($variant,)+
+        }
+
+        impl LinkerFlavor {
+            pub const fn one_of() -> &'static str {
+                concat!("one of: ", $($string, " ",)+)
+            }
+
+            pub fn from_str(s: &str) -> Option<Self> {
+                Some(match s {
+                    $($string => LinkerFlavor::$variant,)+
+                    _ => return None,
+                })
+            }
+
+            pub fn desc(&self) -> &str {
+                match *self {
+                    $(LinkerFlavor::$variant => $string,)+
+                }
+            }
+        }
+
+        impl ToJson for LinkerFlavor {
+            fn to_json(&self) -> Json {
+                self.desc().to_json()
+            }
+        }
+    }
+}
+
+linker_flavor! {
+    (Em, "em"),
+    (Gcc, "gcc"),
+    (Ld, "ld"),
+    (Msvc, "msvc"),
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub enum PanicStrategy {
     Unwind,
index 5ef79359140f775bc6bd6396c22926dfd0d04b5d..802a8c77db05bc3c77cad41642f91dfece4b24ff 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 use super::apple_ios_base::{opts, Arch};
 
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+neon,+fp-armv8,+cyclone".to_string(),
             eliminate_frame_pointer: false,
index 54eead94986cc9b441854d5ccd207bdaa6d27d9a..7d8610b4a36841bc277d218bfd1e31c6c3ca610e 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
@@ -28,6 +29,7 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 3c5d6308ee6bad7b052ae03eb71991b809554c52..c5cfff0be03ad05851fb1461454492a264dc0b7b 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -26,6 +27,7 @@ pub fn target() -> TargetResult {
         target_os: "freebsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 6ba1732e67f7930937fc493cda5ee3c4aa92b776..5d680504a02d00bff5bb9f1391977cdc4cf1447c 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -23,6 +24,7 @@ pub fn target() -> TargetResult {
         target_os: "fuchsia".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 5f6335d405f5ea40fe49b1e7827c51a9ecc6ead1..043bd881c7290c6062cde4331f495641e9b10b45 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -26,6 +27,7 @@ pub fn target() -> TargetResult {
         arch: "aarch64".to_string(),
         target_os: "linux".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 9791520e9339bbd8ad6908b74e70256abbf83673..49baa1b96cee3b4bdf61dec87801898f386f7ea1 100644 (file)
@@ -8,13 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::TargetOptions;
 
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
     // Many of the symbols defined in compiler-rt are also defined in libgcc.
     // Android's linker doesn't like that by default.
-    base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--allow-multiple-definition".to_string());
     base.is_like_android = true;
     base.position_independent_executables = true;
     base.has_elf_tls = false;
index 3a551a2b124b7cc69edc9856c2660f05a15178b9..159f93a74c68352276ec630b8a2d9b6b05259c9d 100644 (file)
@@ -10,7 +10,7 @@
 
 use std::env;
 
-use target::TargetOptions;
+use target::{LinkArgs, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
@@ -43,7 +43,7 @@ pub fn opts() -> TargetOptions {
         dll_prefix: "lib".to_string(),
         dll_suffix: ".dylib".to_string(),
         archive_format: "bsd".to_string(),
-        pre_link_args: Vec::new(),
+        pre_link_args: LinkArgs::new(),
         exe_allocation_crate: super::maybe_jemalloc(),
         has_elf_tls: version >= (10, 7),
         .. Default::default()
index 17492b8bdcb64bf6537b9e71964872d8639ca41a..2e7d30d969ec4b140c773d744f0e41ca0d9a161f 100644 (file)
@@ -8,9 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use std::io;
 use std::process::Command;
-use target::TargetOptions;
+use target::{LinkArgs, TargetOptions};
 
 use self::Arch::*;
 
@@ -60,7 +61,7 @@ pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
     }
 }
 
-fn build_pre_link_args(arch: Arch) -> Result<Vec<String>, String> {
+fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> {
     let sdk_name = match arch {
         Armv7 | Armv7s | Arm64 => "iphoneos",
         I386 | X86_64 => "iphonesimulator"
@@ -70,8 +71,14 @@ fn build_pre_link_args(arch: Arch) -> Result<Vec<String>, String> {
 
     let sdk_root = get_sdk_root(sdk_name)?;
 
-    Ok(vec!["-arch".to_string(), arch_name.to_string(),
-         "-Wl,-syslibroot".to_string(), sdk_root])
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc,
+                vec!["-arch".to_string(),
+                     arch_name.to_string(),
+                     "-Wl,-syslibroot".to_string(),
+                     sdk_root]);
+
+    Ok(args)
 }
 
 fn target_cpu(arch: Arch) -> String {
index c7d2df4344cb1efad4e8b22e6e4551751e25cbb5..bccd5a41ab1155b64d7c5cb9baf1e17b4434613f 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -24,6 +25,7 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 77d35edfbd09cc465ef90a0a9afe03684a9d56d5..165d34fe6c7cee980c32489f0e8eec8ecfd35bf1 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+v6".to_string(),
index b183412be1934853bed150bfe546c3141d014cd3..731021d979bc4158db8115bcf560a20f9b569f8e 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+v6,+vfp2".to_string(),
index 261d4353c7a09f6b2623b2c109ed7df084e41cb0..f81bcd78b03aada993d5d78bb13b759df4685a9e 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -29,6 +30,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 1443dcf5bad418327f65be7807ee1bf31f4fe504..6c47678ede6adb4067417f33a56504dbc4c57e6d 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -29,6 +30,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 37216e20762d4970754319718206dcb94899f2b1..200c6ab74cc6db2a6c9dadd977b908a3a5aafe62 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -21,6 +22,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+soft-float".to_string(),
@@ -31,4 +33,3 @@ pub fn target() -> TargetResult {
         }
     })
 }
-
index 9e9c443930624311c36e6f8483f8624b5bcf9f13..4d8745828329431459dee1f0120ffff270a92bbf 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 use super::apple_ios_base::{opts, Arch};
 
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
index 36f409b7948c27ace4ef2e8b6698bff9036ac2f9..0c90e834006f16734761a850aa3fc694abdaf832 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 // See https://developer.android.com/ndk/guides/abis.html#v7a
@@ -27,6 +28,7 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 96ccedd5bea5c4b59a0f6a37349d97550e8784c9..d3a6a68449c39f0ad217d7ed4108bbd4bf3e7538 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -21,6 +22,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
@@ -32,4 +34,3 @@ pub fn target() -> TargetResult {
         }
     })
 }
-
index 8f66e6a4f58d484ac385ff5830575eb7fcb47436..5086cd44f7ac947522ba5688231a3e095c1fee24 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -30,6 +31,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
index 6edde6e73efd34415ce62bd70a9b77dd347dcfdc..96c89a7ed3bd58e21caebb77511832f1f1e35468 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 use super::apple_ios_base::{opts, Arch};
 
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
             max_atomic_width: Some(64),
index 4d38b0d1705962afa24e58c81801073ea0569d67..b884d4e54101e8ef6eac7705b1f4048b2d99173a 100644 (file)
@@ -8,10 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{Target, TargetOptions};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions};
 use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Em,
+                vec!["-s".to_string(),
+                     "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
+
     let opts = TargetOptions {
         linker: cmd("emcc"),
         ar: cmd("emar"),
@@ -24,7 +30,7 @@ pub fn target() -> Result<Target, String> {
         obj_is_bitcode: true,
         is_like_emscripten: true,
         max_atomic_width: Some(32),
-        post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+        post_link_args: args,
         target_family: Some("unix".to_string()),
         .. Default::default()
     };
@@ -37,6 +43,7 @@ pub fn target() -> Result<Target, String> {
         target_vendor: "unknown".to_string(),
         data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
         arch: "asmjs".to_string(),
+        linker_flavor: LinkerFlavor::Em,
         options: opts,
     })
 }
index dca33e45af7c7ffc656b02609dedf9dc537b4fa5..e44cd393289be3a23afdd0911c4b2e5e5c7dcb6f 100644 (file)
@@ -8,26 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // GNU-style linkers will use this to omit linking to libraries
+        // which don't actually fulfill any relocations, but only for
+        // libraries which follow this flag.  Thus, use it before
+        // specifying libraries to link to.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec![
-            // GNU-style linkers will use this to omit linking to libraries
-            // which don't actually fulfill any relocations, but only for
-            // libraries which follow this flag.  Thus, use it before
-            // specifying libraries to link to.
-            "-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         exe_allocation_crate: super::maybe_jemalloc(),
         .. Default::default()
index dca33e45af7c7ffc656b02609dedf9dc537b4fa5..e44cd393289be3a23afdd0911c4b2e5e5c7dcb6f 100644 (file)
@@ -8,26 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // GNU-style linkers will use this to omit linking to libraries
+        // which don't actually fulfill any relocations, but only for
+        // libraries which follow this flag.  Thus, use it before
+        // specifying libraries to link to.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec![
-            // GNU-style linkers will use this to omit linking to libraries
-            // which don't actually fulfill any relocations, but only for
-            // libraries which follow this flag.  Thus, use it before
-            // specifying libraries to link to.
-            "-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         exe_allocation_crate: super::maybe_jemalloc(),
         .. Default::default()
index 8c517224201b2fe7b2e44b5a7812055c9a5cbfb0..c6207cdc4d9c18efa6a76a1102af11b7bb897024 100644 (file)
@@ -8,30 +8,34 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // We want to be able to strip as much executable code as possible
+        // from the linker command line, and this flag indicates to the
+        // linker that it can avoid linking in dynamic libraries that don't
+        // actually satisfy any symbols up to that point (as with many other
+        // resolutions the linker does). This option only applies to all
+        // following libraries so we're sure to pass it as one of the first
+        // arguments.
+        // FIXME: figure out whether these linker args are desirable
+        //"-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        //"-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec![
-            // We want to be able to strip as much executable code as possible
-            // from the linker command line, and this flag indicates to the
-            // linker that it can avoid linking in dynamic libraries that don't
-            // actually satisfy any symbols up to that point (as with many other
-            // resolutions the linker does). This option only applies to all
-            // following libraries so we're sure to pass it as one of the first
-            // arguments.
-            // FIXME: figure out whether these linker args are desirable
-            //"-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            //"-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
index 319ada4f8e17c11b05f56aa50fdebd75c805aca2..a6383179f3ae60292fb2b9baf7d38430a6002a71 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 use super::apple_ios_base::{opts, Arch};
 
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             max_atomic_width: Some(64),
             .. base
index d3b09d9a0f1121354a76ce92cb56194e27b0b031..6b14972e9f7543d3613b8f0c8e16071c4f4b00ab 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::apple_base::opts();
     base.cpu = "yonah".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
 
     Ok(Target {
         llvm_target: "i686-apple-darwin".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "macos".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index f8a8f5a3500befb6a1d7a789e7fb2ff078d07421..a5390cbfb725803f68587dd303e2e664da7e9dff 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
@@ -31,6 +32,7 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 29477261392079332e3e03ed3ba4b13c3fa3c992..4a736a93be7d7867fc9dd60d69c1e65cb72505ff 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -18,7 +19,8 @@ pub fn target() -> TargetResult {
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
-    base.pre_link_args.push("-Wl,--large-address-aware".to_string());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string());
 
     Ok(Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
@@ -29,6 +31,7 @@ pub fn target() -> TargetResult {
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "pc".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 2290d2057f13076f28ae40ba66e9a9bbaeceaf3e..17fe306804f4a673abfe39d48dc16de527c1ca43 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -17,12 +18,13 @@ pub fn target() -> TargetResult {
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
-    base.pre_link_args.push("/LARGEADDRESSAWARE".to_string());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string());
 
     // Ensure the linker will only produce an image if it can also produce a table of
     // the image's safe exception handlers.
     // https://msdn.microsoft.com/en-us/library/9a89h429.aspx
-    base.pre_link_args.push("/SAFESEH".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string());
 
     Ok(Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
@@ -33,6 +35,7 @@ pub fn target() -> TargetResult {
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
         target_vendor: "pc".to_string(),
+        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     })
 }
index d8f8431e66e7fa51b3937a8ced9dfedb78d09c3f..052bc23c119ea0a85e013153411d2aae42b69ff6 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
 
     Ok(Target {
         llvm_target: "i686-unknown-dragonfly".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "dragonfly".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index ddbc74f25c9cdd9533283ea759a040239b808a26..d77a9cca2683d9904f50a90320b1093cf34ba035 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::freebsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
 
     Ok(Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "freebsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 9078206c9e069cf3b98ee93c19626d217299d0c3..b0e67bd90ddde351fbc689c37d2b61d69b34912f 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::haiku_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
 
     Ok(Target {
         llvm_target: "i686-unknown-haiku".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "haiku".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index bf9c28b0c10e5ada26c1c2b13462aab4aeb4ff07..3c5c10676260ef9dd847589abd383bdfd51c17c0 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
 
     Ok(Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index ced59448f7f65d83b3118368408ab92a471dc7b1..3ed8c94d0bf2a834c3798fe1897e5c00736ec04a 100644 (file)
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
-    base.pre_link_args.push("-Wl,-melf_i386".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string());
 
     // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
     // implementation, apparently relies on frame pointers existing... somehow.
@@ -40,6 +41,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index e7e2ee3f9056a09f8af19394836052c9b8fc81e9..fc92e5aee6af1857bb603bbf65fa460eca8b54c6 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
 
     Ok(Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "netbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 81efd37386a0f9232148e4d83c068526f3c634be..7ef68bd6d9c3a3164c83a6817ca4fe863a0d2127 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::openbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
 
     Ok(Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "openbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 891e7dda14a2a4d931e3171966e97d4e7a53fb1e..f4265e0eb1462d2bd7bc5abf466088aa369ad869 100644 (file)
@@ -8,17 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{Target, TargetOptions, TargetResult};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(LinkerFlavor::Gcc,
+                         vec!["--pnacl-exceptions=sjlj".to_string(),
+                              "--target=le32-unknown-nacl".to_string(),
+                              "-Wl,--start-group".to_string()]);
+    let mut post_link_args = LinkArgs::new();
+    post_link_args.insert(LinkerFlavor::Gcc,
+                          vec!["-Wl,--end-group".to_string()]);
+
     let opts = TargetOptions {
         linker: "pnacl-clang".to_string(),
         ar: "pnacl-ar".to_string(),
 
-        pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(),
-                            "--target=le32-unknown-nacl".to_string(),
-                            "-Wl,--start-group".to_string()],
-        post_link_args: vec!["-Wl,--end-group".to_string()],
+        pre_link_args: pre_link_args,
+        post_link_args: post_link_args,
         dynamic_linking: false,
         executables: true,
         exe_suffix: ".pexe".to_string(),
@@ -36,6 +44,7 @@ pub fn target() -> TargetResult {
         target_vendor: "unknown".to_string(),
         data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
         arch: "le32".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: opts,
     })
 }
index 4b2ae9c8e699c1e23ca0f056afff69d02faf1ea1..722d2fa16ef7a06a23689366bbf3af017cc0984f 100644 (file)
@@ -8,29 +8,33 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // We want to be able to strip as much executable code as possible
+        // from the linker command line, and this flag indicates to the
+        // linker that it can avoid linking in dynamic libraries that don't
+        // actually satisfy any symbols up to that point (as with many other
+        // resolutions the linker does). This option only applies to all
+        // following libraries so we're sure to pass it as one of the first
+        // arguments.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec![
-            // We want to be able to strip as much executable code as possible
-            // from the linker command line, and this flag indicates to the
-            // linker that it can avoid linking in dynamic libraries that don't
-            // actually satisfy any symbols up to that point (as with many other
-            // resolutions the linker does). This option only applies to all
-            // following libraries so we're sure to pass it as one of the first
-            // arguments.
-            "-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         exe_allocation_crate: super::maybe_jemalloc(),
         has_elf_tls: true,
index 18cca425a32c8c43452f34f304d3c8cc5cf4bbf3..236f2c1ef0aa3a983b1b3df47eca904fa8264d22 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::TargetOptions;
 
 pub fn opts() -> TargetOptions {
@@ -15,13 +16,13 @@ pub fn opts() -> TargetOptions {
 
     // Make sure that the linker/gcc really don't pull in anything, including
     // default objects, libs, etc.
-    base.pre_link_args.push("-nostdlib".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
 
     // At least when this was tested, the linker would not add the
     // `GNU_EH_FRAME` program header to executables generated, which is required
     // when unwinding to locate the unwinding information. I'm not sure why this
     // argument is *not* necessary for normal builds, but it can't hurt!
-    base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string());
 
     // There's a whole bunch of circular dependencies when dealing with MUSL
     // unfortunately. To put this in perspective libc is statically linked to
@@ -45,8 +46,8 @@ pub fn opts() -> TargetOptions {
     // link everything as a group, not stripping anything out until everything
     // is processed. The linker will still perform a pass to strip out object
     // files but it won't do so until all objects/archives have been processed.
-    base.pre_link_args.push("-Wl,-(".to_string());
-    base.post_link_args.push("-Wl,-)".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string());
+    base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]);
 
     // When generating a statically linked executable there's generally some
     // small setup needed which is listed in these files. These are provided by
index c284840ecb4bdbdc3b06714732a85fabbe51d93d..038a70ed6b17ee3e700405f71d6a988e8f9b094a 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
index 17895836fe87b54dba7020dbd5b2d00be9c0ecfd..aed4c4fbb08deb90479fac1533c2d6e848b90847 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
index a6d8fae2536cae8628ab3d3b09fb64553ff442d1..9ef61f9caddcdbaf6bd59001ca142f3e340f8d2b 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2".to_string(),
index e4a6d2a55d9813ea4ea188540edae6126447ff1d..f54790bab970b85b0c67d39b22386db08fca0e80 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
index ccc64ea393b7885694640f22b6373ed7dfedf4f3..59c07efe0fdc1818fe7125413d9dceecf0a89c3d 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "uclibc".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
index 9b8b1d5713f1d950771a36d3da49fe750208d944..ec19cc1a536ad7f45a5b9efffdd6a8ec8630c291 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             cpu: "mips32".to_string(),
index 5693bddd0488a51c780e53dbc07c2e641748e345..00085d18e6d09eb7f8953993d866fc25e5b41a0d 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             cpu: "mips32".to_string(),
             features: "+mips32,+soft-float".to_string(),
index 3acade5a474445f1431585dbc0d62a79fed5a369..b3ca2edec1eda57d60122665c2b3d6654d8e3fe7 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -20,6 +21,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "uclibc".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             cpu: "mips32".to_string(),
index 559418d2c4f5ffae02822040f3ed612b3d8b3085..ca6894a7b70411ae74cb94db2d386f09bc0aa3ae 100644 (file)
@@ -50,7 +50,7 @@
 use std::io::prelude::*;
 use syntax::abi::{Abi, lookup as lookup_abi};
 
-use PanicStrategy;
+use {LinkerFlavor, PanicStrategy};
 
 mod android_base;
 mod apple_base;
@@ -72,6 +72,7 @@
 mod fuchsia_base;
 mod redox_base;
 
+pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
 pub type TargetResult = Result<Target, String>;
 
 macro_rules! supported_targets {
@@ -241,6 +242,8 @@ pub struct Target {
     pub arch: String,
     /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
     pub data_layout: String,
+    /// Linker flavor
+    pub linker_flavor: LinkerFlavor,
     /// Optional settings with defaults.
     pub options: TargetOptions,
 }
@@ -261,7 +264,7 @@ pub struct TargetOptions {
 
     /// Linker arguments that are unconditionally passed *before* any
     /// user-defined libraries.
-    pub pre_link_args: Vec<String>,
+    pub pre_link_args: LinkArgs,
     /// Objects to link before all others, always found within the
     /// sysroot folder.
     pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
@@ -269,13 +272,13 @@ pub struct TargetOptions {
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post_link_objects.  Standard platform
     /// libraries that should be always be linked to, usually go here.
-    pub late_link_args: Vec<String>,
+    pub late_link_args: LinkArgs,
     /// Objects to link after all others, always found within the
     /// sysroot folder.
     pub post_link_objects: Vec<String>,
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
-    pub post_link_args: Vec<String>,
+    pub post_link_args: LinkArgs,
 
     /// Extra arguments to pass to the external assembler (when used)
     pub asm_args: Vec<String>,
@@ -412,8 +415,8 @@ fn default() -> TargetOptions {
             is_builtin: false,
             linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
             ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(),
-            pre_link_args: Vec::new(),
-            post_link_args: Vec::new(),
+            pre_link_args: LinkArgs::new(),
+            post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
             cpu: "generic".to_string(),
             features: "".to_string(),
@@ -445,7 +448,7 @@ fn default() -> TargetOptions {
             pre_link_objects_exe: Vec::new(),
             pre_link_objects_dll: Vec::new(),
             post_link_objects: Vec::new(),
-            late_link_args: Vec::new(),
+            late_link_args: LinkArgs::new(),
             archive_format: "gnu".to_string(),
             custom_unwind_resume: false,
             lib_allocation_crate: "alloc_system".to_string(),
@@ -529,6 +532,10 @@ pub fn from_json(obj: Json) -> TargetResult {
             target_os: get_req_field("os")?,
             target_env: get_opt_field("env", ""),
             target_vendor: get_opt_field("vendor", "unknown"),
+            linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?)
+                .ok_or_else(|| {
+                    format!("linker flavor must be {}", LinkerFlavor::one_of())
+                })?,
             options: Default::default(),
         };
 
@@ -579,17 +586,49 @@ macro_rules! key {
                         .map(|s| s.to_string() );
                 }
             } );
+            ($key_name:ident, LinkerFlavor) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..]).and_then(|o| o.as_string().map(|s| {
+                    LinkerFlavor::from_str(&s).ok_or_else(|| {
+                        Err(format!("'{}' is not a valid value for linker-flavor. \
+                                     Use 'em', 'gcc', 'ld' or 'msvc.", s))
+                    })
+                })).unwrap_or(Ok(()))
+            } );
+            ($key_name:ident, link_args) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object()) {
+                    let mut args = LinkArgs::new();
+                    for (k, v) in obj {
+                        let k = LinkerFlavor::from_str(&k).ok_or_else(|| {
+                            format!("{}: '{}' is not a valid value for linker-flavor. \
+                                     Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
+                        })?;
+
+                        let v = v.as_array().map(|a| {
+                            a
+                                .iter()
+                                .filter_map(|o| o.as_string())
+                                .map(|s| s.to_owned())
+                                .collect::<Vec<_>>()
+                        }).unwrap_or(vec![]);
+
+                        args.insert(k, v);
+                    }
+                    base.options.$key_name = args;
+                }
+            } );
         }
 
         key!(is_builtin, bool);
         key!(linker);
         key!(ar);
-        key!(pre_link_args, list);
+        key!(pre_link_args, link_args);
         key!(pre_link_objects_exe, list);
         key!(pre_link_objects_dll, list);
-        key!(late_link_args, list);
+        key!(late_link_args, link_args);
         key!(post_link_objects, list);
-        key!(post_link_args, list);
+        key!(post_link_args, link_args);
         key!(asm_args, list);
         key!(cpu);
         key!(features);
@@ -734,6 +773,16 @@ macro_rules! target_option_val {
                     d.insert(name.to_string(), self.options.$attr.to_json());
                 }
             } );
+            (link_args - $attr:ident) => ( {
+                let name = (stringify!($attr)).replace("_", "-");
+                if default.$attr != self.options.$attr {
+                    let obj = self.options.$attr
+                        .iter()
+                        .map(|(k, v)| (k.desc().to_owned(), v.clone()))
+                        .collect::<BTreeMap<_, _>>();
+                    d.insert(name.to_string(), obj.to_json());
+                }
+            } );
         }
 
         target_val!(llvm_target);
@@ -743,18 +792,18 @@ macro_rules! target_option_val {
         target_val!(target_os, "os");
         target_val!(target_env, "env");
         target_val!(target_vendor, "vendor");
-        target_val!(arch);
         target_val!(data_layout);
+        target_val!(linker_flavor);
 
         target_option_val!(is_builtin);
         target_option_val!(linker);
         target_option_val!(ar);
-        target_option_val!(pre_link_args);
+        target_option_val!(link_args - pre_link_args);
         target_option_val!(pre_link_objects_exe);
         target_option_val!(pre_link_objects_dll);
-        target_option_val!(late_link_args);
+        target_option_val!(link_args - late_link_args);
         target_option_val!(post_link_objects);
-        target_option_val!(post_link_args);
+        target_option_val!(link_args - post_link_args);
         target_option_val!(asm_args);
         target_option_val!(cpu);
         target_option_val!(features);
index 57179a68afd8e9ccdc79bb1f459296277bca6339..63245fcae767b34841a6cf9448b21c2518ef1a6c 100644 (file)
@@ -8,26 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // GNU-style linkers will use this to omit linking to libraries
+        // which don't actually fulfill any relocations, but only for
+        // libraries which follow this flag.  Thus, use it before
+        // specifying libraries to link to.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec![
-            // GNU-style linkers will use this to omit linking to libraries
-            // which don't actually fulfill any relocations, but only for
-            // libraries which follow this flag.  Thus, use it before
-            // specifying libraries to link to.
-            "-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         .. Default::default()
     }
index 12b8e8bdc88fd931e776664af40136cacf0afd81..2df9b8e03ff535866f8428d5ac9aa88f23693ba4 100644 (file)
@@ -8,10 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // GNU-style linkers will use this to omit linking to libraries
+        // which don't actually fulfill any relocations, but only for
+        // libraries which follow this flag.  Thus, use it before
+        // specifying libraries to link to.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
     TargetOptions {
         dynamic_linking: true,
         executables: true,
@@ -19,16 +32,7 @@ pub fn opts() -> TargetOptions {
         linker_is_gnu: true,
         has_rpath: true,
         is_like_openbsd: true,
-        pre_link_args: vec![
-            // GNU-style linkers will use this to omit linking to libraries
-            // which don't actually fulfill any relocations, but only for
-            // libraries which follow this flag.  Thus, use it before
-            // specifying libraries to link to.
-            "-Wl,--as-needed".to_string(),
-
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-        ],
+        pre_link_args: args,
         position_independent_executables: true,
         exe_allocation_crate: "alloc_system".to_string(),
         .. Default::default()
index 909c5488dcb70374eaae5535870fe9606428af24..55a5bfd1e674621bf02d294439bba4c10a1485a3 100644 (file)
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64".to_string();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
     // see #36994
@@ -28,6 +29,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index a692346ca0ffeeb95a88bf2183f3eea8b6ca4f90..c22bc3b041a4ee2d41dd0903347015dbab12546b 100644 (file)
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64le".to_string();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
     // see #36994
@@ -28,6 +29,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 284772c43319aedf193fd12af276ea1586adbd14..677d198b1a379a315158c8d13428fe5401ca4665 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
-    base.pre_link_args.push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
     // see #36994
@@ -27,6 +28,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index c5e1e107753ffa80c56b543d5e04e29daa5c689b..f26a86d4bdc0f13c4bc60de2626eaf442e3e882b 100644 (file)
@@ -8,25 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use PanicStrategy;
-use target::TargetOptions;
+use {LinkerFlavor, PanicStrategy};
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
-    TargetOptions {
-        pre_link_args: vec![
-            // We want to be able to strip as much executable code as possible
-            // from the linker command line, and this flag indicates to the
-            // linker that it can avoid linking in dynamic libraries that don't
-            // actually satisfy any symbols up to that point (as with many other
-            // resolutions the linker does). This option only applies to all
-            // following libraries so we're sure to pass it as one of the first
-            // arguments.
-            "-Wl,--as-needed".to_string(),
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // We want to be able to strip as much executable code as possible
+        // from the linker command line, and this flag indicates to the
+        // linker that it can avoid linking in dynamic libraries that don't
+        // actually satisfy any symbols up to that point (as with many other
+        // resolutions the linker does). This option only applies to all
+        // following libraries so we're sure to pass it as one of the first
+        // arguments.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string()
+    ]);
 
-            // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string()
-        ],
+    TargetOptions {
+        pre_link_args: args,
         executables: true,
         relocation_model: "static".to_string(),
         disable_redzone: true,
index 671fb4f4319b35f5d1c592aee2ddf4145dac6524..cc8eb7c4e84243e281e54086220474d7f22c0366 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -31,6 +32,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index f627cc18f0b3d709dbdd513e0ad3de4fba6e2b43..1bd51ac62581f06ee4e5104607376285694473e5 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index f30cebbc2d5a7e91c292eb875d10919794056b9f..bc65a17ce6ea93063743a2d44646133437201150 100644 (file)
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "v9".to_string();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
     Ok(Target {
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "netbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index c88e5a402f2f545e0719b0178848d9314730368d..122b38968a9c0355e74e258c11084408102be7fc 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::solaris_base::opts();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     // llvm calls this "v9"
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
@@ -30,6 +31,7 @@ pub fn target() -> TargetResult {
         target_os: "solaris".to_string(),
         target_env: "".to_string(),
         target_vendor: "sun".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 6c22f98538459ea5711308df1729b475ec60ab97..08bf145e5518ac8911a5ae34c676565437aaea80 100644 (file)
@@ -10,6 +10,7 @@
 
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: "".to_string(),
         target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
index ddad4e3624f3cef16a960f8f5058fcf82f2370e1..13f9cc5f65fb9bd3db0f2ba1fdd66b5a48e0a5c5 100644 (file)
@@ -19,6 +19,7 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -31,6 +32,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: "".to_string(),
         target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             max_atomic_width: Some(32),
index a9fac48e8e5ac39c549ea88439af6d99851d8102..929b6db6fb2c60b7914139ddd3f80776c7d0d37e 100644 (file)
@@ -18,6 +18,7 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -30,6 +31,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: "".to_string(),
         target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the
index ed61dd0459b4d7c23ac8a5012d83ba514d846a12..8d46e7cb90760bb5903a9b6dc29814edd8a18f91 100644 (file)
@@ -10,6 +10,7 @@
 
 // Targets the Cortex-M3 processor (ARMv7-M)
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: "".to_string(),
         target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             max_atomic_width: Some(32),
index b1967fa8f37a7aea5c3052d48d45e24bfbbf4098..a51f59d6ff1925e9222fce68a01ef378c92dec12 100644 (file)
@@ -8,10 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{Target, TargetOptions};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions};
 use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
+    let mut post_link_args = LinkArgs::new();
+    post_link_args.insert(LinkerFlavor::Gcc,
+                          vec!["-s".to_string(),
+                               "BINARYEN=1".to_string(),
+                               "-s".to_string(),
+                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
+
     let opts = TargetOptions {
         linker: cmd("emcc"),
         ar: cmd("emar"),
@@ -26,8 +34,7 @@ pub fn target() -> Result<Target, String> {
         obj_is_bitcode: true,
         is_like_emscripten: true,
         max_atomic_width: Some(32),
-        post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
-                             "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+        post_link_args: post_link_args,
         target_family: Some("unix".to_string()),
         .. Default::default()
     };
@@ -40,6 +47,7 @@ pub fn target() -> Result<Target, String> {
         target_vendor: "unknown".to_string(),
         data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
         arch: "wasm32".to_string(),
+        linker_flavor: LinkerFlavor::Em,
         options: opts,
     })
 }
index db02e142fcc8efac34aca9480845a87696be1cdf..9bde24a28dd9b253ed14c0a1a5f8e3fe4d244921 100644 (file)
@@ -8,26 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
-    TargetOptions {
-        // FIXME(#13846) this should be enabled for windows
-        function_sections: false,
-        linker: "gcc".to_string(),
-        dynamic_linking: true,
-        executables: true,
-        dll_prefix: "".to_string(),
-        dll_suffix: ".dll".to_string(),
-        exe_suffix: ".exe".to_string(),
-        staticlib_prefix: "".to_string(),
-        staticlib_suffix: ".lib".to_string(),
-        no_default_libraries: true,
-        target_family: Some("windows".to_string()),
-        is_like_windows: true,
-        allows_weak_linkage: false,
-        pre_link_args: vec![
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(LinkerFlavor::Gcc, vec![
             // And here, we see obscure linker flags #45. On windows, it has been
             // found to be necessary to have this flag to compile liblibc.
             //
@@ -64,7 +51,34 @@ pub fn opts() -> TargetOptions {
 
             // Do not use the standard system startup files or libraries when linking
             "-nostdlib".to_string(),
-        ],
+        ]);
+
+    let mut late_link_args = LinkArgs::new();
+    late_link_args.insert(LinkerFlavor::Gcc, vec![
+        "-lmingwex".to_string(),
+        "-lmingw32".to_string(),
+        "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
+        "-lmsvcrt".to_string(),
+        "-luser32".to_string(),
+        "-lkernel32".to_string(),
+    ]);
+
+    TargetOptions {
+        // FIXME(#13846) this should be enabled for windows
+        function_sections: false,
+        linker: "gcc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        dll_prefix: "".to_string(),
+        dll_suffix: ".dll".to_string(),
+        exe_suffix: ".exe".to_string(),
+        staticlib_prefix: "".to_string(),
+        staticlib_suffix: ".lib".to_string(),
+        no_default_libraries: true,
+        target_family: Some("windows".to_string()),
+        is_like_windows: true,
+        allows_weak_linkage: false,
+        pre_link_args: pre_link_args,
         pre_link_objects_exe: vec![
             "crt2.o".to_string(),    // mingw C runtime initialization for executables
             "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
@@ -73,14 +87,7 @@ pub fn opts() -> TargetOptions {
             "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
             "rsbegin.o".to_string(),
         ],
-        late_link_args: vec![
-            "-lmingwex".to_string(),
-            "-lmingw32".to_string(),
-            "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
-            "-lmsvcrt".to_string(),
-            "-luser32".to_string(),
-            "-lkernel32".to_string(),
-        ],
+        late_link_args: late_link_args,
         post_link_objects: vec![
             "rsend.o".to_string()
         ],
index efa215b419d7044fed385b8b176d2f664a6e3bc1..421f59aea93bf4acba458dd5622be1641f832746 100644 (file)
@@ -8,10 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Msvc,
+                vec!["/NOLOGO".to_string(),
+                     "/NXCOMPAT".to_string()]);
+
     TargetOptions {
         function_sections: true,
         linker: "link.exe".to_string(),
@@ -56,10 +62,7 @@ pub fn opts() -> TargetOptions {
         target_family: Some("windows".to_string()),
         is_like_windows: true,
         is_like_msvc: true,
-        pre_link_args: vec![
-            "/NOLOGO".to_string(),
-            "/NXCOMPAT".to_string(),
-        ],
+        pre_link_args: args,
         exe_allocation_crate: "alloc_system".to_string(),
 
         .. Default::default()
index b3c1561dbcc0bb06f2556b1a68a1f34244388d41..8fd1b80430f44795aa62ff0749cc301988abfed3 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -15,7 +16,7 @@ pub fn target() -> TargetResult {
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.eliminate_frame_pointer = false;
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
 
     Ok(Target {
         llvm_target: "x86_64-apple-darwin".to_string(),
@@ -26,6 +27,7 @@ pub fn target() -> TargetResult {
         target_os: "macos".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 7a58bb34ce7f6e67eeefb15074917a3ef5ab00c4..bbd81fd86ff578e2e2f9e4cb6576277f21879eb3 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetOptions, TargetResult};
 use super::apple_ios_base::{opts, Arch};
 
@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             max_atomic_width: Some(64),
             .. base
index 321585cd65eb39020824daeaffc3da90b70164d9..10e88d88ee372c97fdb3b27c2479723cf1fa244c 100644 (file)
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::windows_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
     Ok(Target {
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "pc".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index ea8909d213e80b79463cae221a7a634f679b5ca0..b07031c4bf1a3de5b13ba9d196a50b1d17860c8a 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
@@ -24,6 +25,7 @@ pub fn target() -> TargetResult {
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
         target_vendor: "pc".to_string(),
+        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     })
 }
index 33137214396961a05e7fff8139bd7e341ad7da37..eea4389cfd64eaee7e5f8bfd79166ca552e470f6 100644 (file)
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
     base.ar = "x86_64-rumprun-netbsd-ar".to_string();
     base.max_atomic_width = Some(64);
@@ -34,6 +35,7 @@ pub fn target() -> TargetResult {
         target_os: "netbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "rumprun".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 8e4fd94e7bce4375afd14a991f5cb1b5cde92271..fe8691f36950dc5aa31807daf3de80a7e6eaaf7b 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::solaris_base::opts();
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "solaris".to_string(),
         target_env: "".to_string(),
         target_vendor: "sun".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index eda16c29466b54ce5e8a2c2276dfb2ba261d034a..5f87fe177a98c04dfc21c04e5cfff594d06ff175 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::bitrig_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
 
     Ok(Target {
         llvm_target: "x86_64-unknown-bitrig".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "bitrig".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 194efb8fc232254af9523d0ad249a1644bb46aa1..96f608409ffa7610ed9c28a3619f35b2b26e646c 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "dragonfly".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index b127bee163b86ed5df3a610a3d00711eff51c024..500629a16808dd3f88125ec53dfd376bfb36c637 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::freebsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "freebsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 08fe17a556ecca1f74a5f81d7bc0a700ebd26eb0..6e37896d4148bd1790d10fc41b16f5a713db7b91 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-fuchsia".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "fuchsia".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 7cf0599037c1e97efd71fac637aac8fbfad3af4b..7fab9128b2952f538569539b637dafee5daf1d5c 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::haiku_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
 
     Ok(Target {
         llvm_target: "x86_64-unknown-haiku".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "haiku".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index f95bcb556e57f0bf3ac2838e6c36f7acf67de42d..f73055cebaa2e2ff0f94a3cb2ce6eee402501989 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index c3bf9dcca6ee4ff9e24d0e2522b3aae4a59a07e9..38b9c0bace52b1fe73530d66ab0f86549196706f 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 87a7c184644d57082215e8cf465c38674529f981..6fe2e3fc08e23e30de5bb716949d8d8d0a70c775 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "netbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index e9d645b0d38f259f74f4a29d21aa2c1f3b08ba34..b292b5fc1e4e4720f6a771088509555b33299b4c 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::openbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "openbsd".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index cecac06b235275a6b18162e7b532c9168ff983c3..a693e76099bdafa27b8f013d58e56bd438cc50ac 100644 (file)
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use LinkerFlavor;
 use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::redox_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.pre_link_args.push("-m64".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
     Ok(Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
@@ -25,6 +26,7 @@ pub fn target() -> TargetResult {
         target_os: "redox".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     })
 }
index 29fbcb70756ba08adeca9c87caff42d202225183..adb22197226023fcb80731626f1ecc97255275f7 100644 (file)
 use std::mem;
 use std::collections::range::RangeArgument;
 use std::collections::Bound::{Excluded, Included, Unbounded};
+use std::mem::ManuallyDrop;
 
 pub unsafe trait Array {
     type Element;
-    type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
+    type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
     const LEN: usize;
 }
 
@@ -66,7 +67,7 @@ impl<A: Array> ArrayVec<A> {
     pub fn new() -> Self {
         ArrayVec {
             count: 0,
-            values: Default::default(),
+            values: unsafe { ::std::mem::uninitialized() },
         }
     }
 
@@ -81,7 +82,7 @@ pub unsafe fn set_len(&mut self, len: usize) {
     /// Panics when the stack vector is full.
     pub fn push(&mut self, el: A::Element) {
         let arr = &mut self.values as &mut [ManuallyDrop<_>];
-        arr[self.count] = ManuallyDrop { value: el };
+        arr[self.count] = ManuallyDrop::new(el);
         self.count += 1;
     }
 
@@ -90,8 +91,8 @@ pub fn pop(&mut self) -> Option<A::Element> {
             let arr = &mut self.values as &mut [ManuallyDrop<_>];
             self.count -= 1;
             unsafe {
-                let value = ptr::read(&arr[self.count]);
-                Some(value.value)
+                let value = ptr::read(&*arr[self.count]);
+                Some(value)
             }
         } else {
             None
@@ -210,7 +211,7 @@ impl<A: Array> Iterator for Iter<A> {
     fn next(&mut self) -> Option<A::Element> {
         let arr = &self.store as &[ManuallyDrop<_>];
         unsafe {
-            self.indices.next().map(|i| ptr::read(&arr[i]).value)
+            self.indices.next().map(|i| ptr::read(&*arr[i]))
         }
     }
 
@@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> {
 
     #[inline]
     fn next(&mut self) -> Option<A::Element> {
-        self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
+        self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -295,25 +296,3 @@ fn into_iter(self) -> Self::IntoIter {
         self.iter_mut()
     }
 }
-
-// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
-#[allow(unions_with_drop_fields)]
-pub union ManuallyDrop<T> {
-    value: T,
-    #[allow(dead_code)]
-    empty: (),
-}
-
-impl<T> ManuallyDrop<T> {
-    fn new() -> ManuallyDrop<T> {
-        ManuallyDrop {
-            empty: ()
-        }
-    }
-}
-
-impl<T> Default for ManuallyDrop<T> {
-    fn default() -> Self {
-        ManuallyDrop::new()
-    }
-}
index c1735b4a4ec9a588156757293152deb775fa1129..72c533a74618b8185eae1cb22807539ef56cdb4f 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(conservative_impl_trait)]
 #![feature(discriminant_value)]
 #![feature(specialization)]
+#![feature(manually_drop)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
index c90dde3a5f6e0232694ae37dec7e11e70c91b446..1a892b73aa5d771c86f6f2dd1c09796763647997 100644 (file)
@@ -517,6 +517,16 @@ fn build_controller(&mut self,
             control.make_glob_map = resolve::MakeGlobMap::Yes;
         }
 
+        if sess.print_fuel_crate.is_some() {
+            let old_callback = control.compilation_done.callback;
+            control.compilation_done.callback = box move |state| {
+                old_callback(state);
+                let sess = state.session;
+                println!("Fuel used by {}: {}",
+                    sess.print_fuel_crate.as_ref().unwrap(),
+                    sess.print_fuel.get());
+            }
+        }
         control
     }
 }
index 367b85ac726db0aa49be0add1b7a59971713e526..a52628ceb47abf75382f84b1dda1b8247b18db1e 100644 (file)
@@ -21,6 +21,8 @@
 use std::io;
 use std::rc::Rc;
 use term;
+use std::collections::HashMap;
+use std::cmp::min;
 
 /// Emitter trait for emitting errors.
 pub trait Emitter {
@@ -156,15 +158,6 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
                 }
                 let lo = cm.lookup_char_pos(span_label.span.lo);
                 let mut hi = cm.lookup_char_pos(span_label.span.hi);
-                let mut is_minimized = false;
-
-                // If the span is long multi-line, simplify down to the span of one character
-                let max_multiline_span_length = 8;
-                if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length {
-                    hi.line = lo.line;
-                    hi.col = CharPos(lo.col.0 + 1);
-                    is_minimized = true;
-                }
 
                 // Watch out for "empty spans". If we get a span like 6..6, we
                 // want to just display a `^` at 6, so convert that to
@@ -175,16 +168,7 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
                     hi.col = CharPos(lo.col.0 + 1);
                 }
 
-                let mut ann = Annotation {
-                    start_col: lo.col.0,
-                    end_col: hi.col.0,
-                    is_primary: span_label.is_primary,
-                    label: span_label.label.clone(),
-                    annotation_type: AnnotationType::Singleline,
-                };
-                if is_minimized {
-                    ann.annotation_type = AnnotationType::Minimized;
-                } else if lo.line != hi.line {
+                let ann_type = if lo.line != hi.line {
                     let ml = MultilineAnnotation {
                         depth: 1,
                         line_start: lo.line,
@@ -194,8 +178,17 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
                         is_primary: span_label.is_primary,
                         label: span_label.label.clone(),
                     };
-                    ann.annotation_type = AnnotationType::Multiline(ml.clone());
-                    multiline_annotations.push((lo.file.clone(), ml));
+                    multiline_annotations.push((lo.file.clone(), ml.clone()));
+                    AnnotationType::Multiline(ml)
+                } else {
+                    AnnotationType::Singleline
+                };
+                let ann = Annotation {
+                    start_col: lo.col.0,
+                    end_col: hi.col.0,
+                    is_primary: span_label.is_primary,
+                    label: span_label.label.clone(),
+                    annotation_type: ann_type,
                 };
 
                 if !ann.is_multiline() {
@@ -233,9 +226,15 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
                 max_depth = ann.depth;
             }
             add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
-            for line in ann.line_start + 1..ann.line_end {
+            let middle = min(ann.line_start + 4, ann.line_end);
+            for line in ann.line_start + 1..middle {
                 add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
             }
+            if middle < ann.line_end - 1 {
+                for line in ann.line_end - 1..ann.line_end {
+                    add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+                }
+            }
             add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
         }
         for file_vec in output.iter_mut() {
@@ -249,16 +248,11 @@ fn render_source_line(&self,
                           file: Rc<FileMap>,
                           line: &Line,
                           width_offset: usize,
-                          multiline_depth: usize) {
+                          code_offset: usize) -> Vec<(usize, Style)> {
         let source_string = file.get_line(line.line_index - 1)
             .unwrap_or("");
 
         let line_offset = buffer.num_lines();
-        let code_offset = if multiline_depth == 0 {
-            width_offset
-        } else {
-            width_offset + multiline_depth + 1
-        };
 
         // First create the source line we will highlight.
         buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
@@ -286,7 +280,7 @@ fn render_source_line(&self,
         //      previous borrow of `vec` occurs here
         //
         // For this reason, we group the lines into "highlight lines"
-        // and "annotations lines", where the highlight lines have the `~`.
+        // and "annotations lines", where the highlight lines have the `^`.
 
         // Sort the annotations by (start, end col)
         let mut annotations = line.annotations.clone();
@@ -410,25 +404,9 @@ fn render_source_line(&self,
         // If there are no annotations or the only annotations on this line are
         // MultilineLine, then there's only code being shown, stop processing.
         if line.annotations.is_empty() || line.annotations.iter()
-            .filter(|a| {
-                // Set the multiline annotation vertical lines to the left of
-                // the code in this line.
-                if let AnnotationType::MultilineLine(depth) = a.annotation_type {
-                    buffer.putc(line_offset,
-                                width_offset + depth - 1,
-                                '|',
-                                if a.is_primary {
-                                    Style::UnderlinePrimary
-                                } else {
-                                    Style::UnderlineSecondary
-                                });
-                    false
-                } else {
-                    true
-                }
-            }).collect::<Vec<_>>().len() == 0
+            .filter(|a| !a.is_line()).collect::<Vec<_>>().len() == 0
         {
-            return;
+            return vec![];
         }
 
         // Write the colunmn separator.
@@ -483,8 +461,7 @@ fn render_source_line(&self,
             }
         }
 
-        // Write the vertical lines for multiline spans and for labels that are
-        // on a different line as the underline.
+        // Write the vertical lines for labels that are on a different line as the underline.
         //
         // After this we will have:
         //
@@ -492,7 +469,7 @@ fn render_source_line(&self,
         //   |  __________
         //   | |    |
         //   | |
-        // 3 | |
+        // 3 |
         // 4 | | }
         //   | |_
         for &(pos, annotation) in &annotations_position {
@@ -528,16 +505,6 @@ fn render_source_line(&self,
                                     style);
                     }
                 }
-                AnnotationType::MultilineLine(depth) => {
-                    // the first line will have already be filled when we checked
-                    // wether there were any annotations for this line.
-                    for p in line_offset + 1..line_offset + line_len + 2 {
-                        buffer.putc(p,
-                                    width_offset + depth - 1,
-                                    '|',
-                                    style);
-                    }
-                }
                 _ => (),
             }
         }
@@ -548,11 +515,11 @@ fn render_source_line(&self,
         //
         // 2 |   fn foo() {
         //   |  __________ starting here...
-        //   | |    |
-        //   | |    something about `foo`
-        // 3 | |
-        // 4 | | }
-        //   | |_  ...ending here: test
+        //   |      |
+        //   |      something about `foo`
+        // 3 |
+        // 4 |   }
+        //   |  _  ...ending here: test
         for &(pos, annotation) in &annotations_position {
             let style = if annotation.is_primary {
                 Style::LabelPrimary
@@ -591,11 +558,11 @@ fn render_source_line(&self,
         //
         // 2 |   fn foo() {
         //   |  ____-_____^ starting here...
-        //   | |    |
-        //   | |    something about `foo`
-        // 3 | |
-        // 4 | | }
-        //   | |_^  ...ending here: test
+        //   |      |
+        //   |      something about `foo`
+        // 3 |
+        // 4 |   }
+        //   |  _^  ...ending here: test
         for &(_, annotation) in &annotations_position {
             let (underline, style) = if annotation.is_primary {
                 ('^', Style::UnderlinePrimary)
@@ -609,6 +576,20 @@ fn render_source_line(&self,
                             style);
             }
         }
+        annotations_position.iter().filter_map(|&(_, annotation)| {
+            match annotation.annotation_type {
+                AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => {
+                    let style = if annotation.is_primary {
+                        Style::LabelPrimary
+                    } else {
+                        Style::LabelSecondary
+                    };
+                    Some((p, style))
+                },
+                _ => None
+            }
+
+        }).collect::<Vec<_>>()
     }
 
     fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
@@ -902,22 +883,64 @@ fn emit_message_default(&mut self,
             let buffer_msg_line_offset = buffer.num_lines();
             draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
 
+            // Contains the vertical lines' positions for active multiline annotations
+            let mut multilines = HashMap::new();
+
             // Next, output the annotate source for this file
             for line_idx in 0..annotated_file.lines.len() {
-                self.render_source_line(&mut buffer,
-                                        annotated_file.file.clone(),
-                                        &annotated_file.lines[line_idx],
-                                        3 + max_line_num_len,
-                                        annotated_file.multiline_depth);
+                let previous_buffer_line = buffer.num_lines();
+
+                let width_offset = 3 + max_line_num_len;
+                let code_offset = if annotated_file.multiline_depth == 0 {
+                    width_offset
+                } else {
+                    width_offset + annotated_file.multiline_depth + 1
+                };
+
+                let depths = self.render_source_line(&mut buffer,
+                                                     annotated_file.file.clone(),
+                                                     &annotated_file.lines[line_idx],
+                                                     width_offset,
+                                                     code_offset);
 
+                let mut to_add = HashMap::new();
+
+                for (depth, style) in depths {
+                    if multilines.get(&depth).is_some() {
+                        multilines.remove(&depth);
+                    } else {
+                        to_add.insert(depth, style);
+                    }
+                }
+
+                // Set the multiline annotation vertical lines to the left of
+                // the code in this line.
+                for (depth, style) in &multilines {
+                    for line in previous_buffer_line..buffer.num_lines() {
+                        draw_multiline_line(&mut buffer,
+                                            line,
+                                            width_offset,
+                                            *depth,
+                                            *style);
+                    }
+                }
                 // check to see if we need to print out or elide lines that come between
-                // this annotated line and the next one
+                // this annotated line and the next one.
                 if line_idx < (annotated_file.lines.len() - 1) {
                     let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
                                          annotated_file.lines[line_idx].line_index;
                     if line_idx_delta > 2 {
                         let last_buffer_line_num = buffer.num_lines();
                         buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
+
+                        // Set the multiline annotation vertical lines on `...` bridging line.
+                        for (depth, style) in &multilines {
+                            draw_multiline_line(&mut buffer,
+                                                last_buffer_line_num,
+                                                width_offset,
+                                                *depth,
+                                                *style);
+                        }
                     } else if line_idx_delta == 2 {
                         let unannotated_line = annotated_file.file
                             .get_line(annotated_file.lines[line_idx].line_index)
@@ -932,11 +955,21 @@ fn emit_message_default(&mut self,
                                     Style::LineNumber);
                         draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
                         buffer.puts(last_buffer_line_num,
-                                    3 + max_line_num_len,
+                                    code_offset,
                                     &unannotated_line,
                                     Style::Quotation);
+
+                        for (depth, style) in &multilines {
+                            draw_multiline_line(&mut buffer,
+                                                last_buffer_line_num,
+                                                width_offset,
+                                                *depth,
+                                                *style);
+                        }
                     }
                 }
+
+                multilines.extend(&to_add);
             }
         }
 
@@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
     buffer.puts(line, col, "= ", Style::LineNumber);
 }
 
+fn draw_multiline_line(buffer: &mut StyledBuffer,
+                       line: usize,
+                       offset: usize,
+                       depth: usize,
+                       style: Style)
+{
+    buffer.putc(line, offset + depth - 1, '|', style);
+}
+
 fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
     let extra = if inclusive {
         1
index 5debbf4d37c20286fab1be9ed9b763888c84327f..9aa4682e1afcbfc2f8239803c64eaa0a6bb409d5 100644 (file)
@@ -97,9 +97,6 @@ pub enum AnnotationType {
     /// Annotation under a single line of code
     Singleline,
 
-    /// Annotation under the first character of a multiline span
-    Minimized,
-
     /// Annotation enclosing the first and last character of a multiline span
     Multiline(MultilineAnnotation),
 
@@ -118,6 +115,9 @@ pub enum AnnotationType {
     /// Annotation marking the last character of a fully shown multiline span
     MultilineEnd(usize),
     /// Line at the left enclosing the lines of a fully shown multiline span
+    // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
+    // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
+    // `draw_multiline_line`.
     MultilineLine(usize),
 }
 
@@ -144,13 +144,6 @@ pub struct Annotation {
 }
 
 impl Annotation {
-    pub fn is_minimized(&self) -> bool {
-        match self.annotation_type {
-            AnnotationType::Minimized => true,
-            _ => false,
-        }
-    }
-
     /// Wether this annotation is a vertical line placeholder.
     pub fn is_line(&self) -> bool {
         if let AnnotationType::MultilineLine(_) = self.annotation_type {
index 529afe0215e53672eebee1ea1538e3c9c87719ae..2318bb81affe67c44c50c0cbf82a1f5a5c24f87d 100644 (file)
@@ -733,7 +733,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
                 });
 
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
-                    let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
+                    let discr_size = Primitive::Int(discr).size(cx.tcx).bytes();
 
                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
                       t, size.bytes(), layout);
index 7d5887e699fd7fdb2329291736ca32a7130ec1f6..a8def4bafd864b6e4203025c2082f233d9f87eb6 100644 (file)
@@ -217,6 +217,9 @@ fn main() {
     // hack around this by replacing the host triple with the target and pray
     // that those -L directories are the same!
     let mut cmd = Command::new(&llvm_config);
+    if let Some(link_arg) = llvm_link_arg {
+        cmd.arg(link_arg);
+    }
     cmd.arg("--ldflags");
     for lib in output(&mut cmd).split_whitespace() {
         if lib.starts_with("-LIBPATH:") {
index 453f65eb762f86522f32de212f788662469f9a28..7be80a757ca0166a300c275e96a6ca8f1320cd3b 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
+use llvm::{self, ValueRef, AttributePlace};
 use base;
 use builder::Builder;
 use common::{type_is_fat_ptr, C_uint};
 use cabi_sparc64;
 use cabi_nvptx;
 use cabi_nvptx64;
-use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
+use machine::llalign_of_min;
 use type_::Type;
 use type_of;
 
 use rustc::hir;
 use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
 
 use libc::c_uint;
 use std::cmp;
+use std::iter;
 
 pub use syntax::abi::Abi;
 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
-use rustc::ty::layout::Layout;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 enum ArgKind {
@@ -132,33 +133,293 @@ pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
         }
     }
 }
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum RegKind {
+    Integer,
+    Float,
+    Vector
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Reg {
+    pub kind: RegKind,
+    pub size: Size,
+}
+
+macro_rules! reg_ctor {
+    ($name:ident, $kind:ident, $bits:expr) => {
+        pub fn $name() -> Reg {
+            Reg {
+                kind: RegKind::$kind,
+                size: Size::from_bits($bits)
+            }
+        }
+    }
+}
+
+impl Reg {
+    reg_ctor!(i8, Integer, 8);
+    reg_ctor!(i16, Integer, 16);
+    reg_ctor!(i32, Integer, 32);
+    reg_ctor!(i64, Integer, 64);
+
+    reg_ctor!(f32, Float, 32);
+    reg_ctor!(f64, Float, 64);
+}
+
+impl Reg {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        match self.kind {
+            RegKind::Integer => Type::ix(ccx, self.size.bits()),
+            RegKind::Float => {
+                match self.size.bits() {
+                    32 => Type::f32(ccx),
+                    64 => Type::f64(ccx),
+                    _ => bug!("unsupported float: {:?}", self)
+                }
+            }
+            RegKind::Vector => {
+                Type::vector(&Type::i8(ccx), self.size.bytes())
+            }
+        }
+    }
+}
+
+/// An argument passed entirely registers with the
+/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
+#[derive(Copy, Clone)]
+pub struct Uniform {
+    pub unit: Reg,
+
+    /// The total size of the argument, which can be:
+    /// * equal to `unit.size` (one scalar/vector)
+    /// * a multiple of `unit.size` (an array of scalar/vectors)
+    /// * if `unit.kind` is `Integer`, the last element
+    ///   can be shorter, i.e. `{ i64, i64, i32 }` for
+    ///   64-bit integers with a total size of 20 bytes
+    pub total: Size,
+}
+
+impl From<Reg> for Uniform {
+    fn from(unit: Reg) -> Uniform {
+        Uniform {
+            unit,
+            total: unit.size
+        }
+    }
+}
+
+impl Uniform {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        let llunit = self.unit.llvm_type(ccx);
+
+        if self.total <= self.unit.size {
+            return llunit;
+        }
+
+        let count = self.total.bytes() / self.unit.size.bytes();
+        let rem_bytes = self.total.bytes() % self.unit.size.bytes();
+
+        if rem_bytes == 0 {
+            return Type::array(&llunit, count);
+        }
+
+        // Only integers can be really split further.
+        assert_eq!(self.unit.kind, RegKind::Integer);
+
+        let args: Vec<_> = (0..count).map(|_| llunit)
+            .chain(iter::once(Type::ix(ccx, rem_bytes * 8)))
+            .collect();
+
+        Type::struct_(ccx, &args, false)
+    }
+}
+
+pub trait LayoutExt<'tcx> {
+    fn is_aggregate(&self) -> bool;
+    fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg>;
+}
+
+impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
+    fn is_aggregate(&self) -> bool {
+        match *self.layout {
+            Layout::Scalar { .. } |
+            Layout::RawNullablePointer { .. } |
+            Layout::CEnum { .. } |
+            Layout::Vector { .. } => false,
+
+            Layout::Array { .. } |
+            Layout::FatPointer { .. } |
+            Layout::Univariant { .. } |
+            Layout::UntaggedUnion { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => true
+        }
+    }
+
+    fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
+        match *self.layout {
+            // The primitives for this algorithm.
+            Layout::Scalar { value, .. } |
+            Layout::RawNullablePointer { value, .. } => {
+                let kind = match value {
+                    layout::Int(_) |
+                    layout::Pointer => RegKind::Integer,
+                    layout::F32 |
+                    layout::F64 => RegKind::Float
+                };
+                Some(Reg {
+                    kind,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::CEnum { .. } => {
+                Some(Reg {
+                    kind: RegKind::Integer,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::Vector { .. } => {
+                Some(Reg {
+                    kind: RegKind::Integer,
+                    size: self.size(ccx)
+                })
+            }
+
+            Layout::Array { count, .. } => {
+                if count > 0 {
+                    self.field(ccx, 0).homogenous_aggregate(ccx)
+                } else {
+                    None
+                }
+            }
+
+            Layout::Univariant { ref variant, .. } => {
+                let mut unaligned_offset = Size::from_bytes(0);
+                let mut result = None;
+
+                for i in 0..self.field_count() {
+                    if unaligned_offset != variant.offsets[i] {
+                        return None;
+                    }
+
+                    let field = self.field(ccx, i);
+                    match (result, field.homogenous_aggregate(ccx)) {
+                        // The field itself must be a homogenous aggregate.
+                        (_, None) => return None,
+                        // If this is the first field, record the unit.
+                        (None, Some(unit)) => {
+                            result = Some(unit);
+                        }
+                        // For all following fields, the unit must be the same.
+                        (Some(prev_unit), Some(unit)) => {
+                            if prev_unit != unit {
+                                return None;
+                            }
+                        }
+                    }
+
+                    // Keep track of the offset (without padding).
+                    let size = field.size(ccx);
+                    match unaligned_offset.checked_add(size, ccx) {
+                        Some(offset) => unaligned_offset = offset,
+                        None => return None
+                    }
+                }
+
+                // There needs to be no padding.
+                if unaligned_offset != self.size(ccx) {
+                    None
+                } else {
+                    result
+                }
+            }
+
+            Layout::UntaggedUnion { .. } => {
+                let mut max = Size::from_bytes(0);
+                let mut result = None;
+
+                for i in 0..self.field_count() {
+                    let field = self.field(ccx, i);
+                    match (result, field.homogenous_aggregate(ccx)) {
+                        // The field itself must be a homogenous aggregate.
+                        (_, None) => return None,
+                        // If this is the first field, record the unit.
+                        (None, Some(unit)) => {
+                            result = Some(unit);
+                        }
+                        // For all following fields, the unit must be the same.
+                        (Some(prev_unit), Some(unit)) => {
+                            if prev_unit != unit {
+                                return None;
+                            }
+                        }
+                    }
+
+                    // Keep track of the offset (without padding).
+                    let size = field.size(ccx);
+                    if size > max {
+                        max = size;
+                    }
+                }
+
+                // There needs to be no padding.
+                if max != self.size(ccx) {
+                    None
+                } else {
+                    result
+                }
+            }
+
+            // Rust-specific types, which we can ignore for C ABIs.
+            Layout::FatPointer { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => None
+        }
+    }
+}
+
+pub enum CastTarget {
+    Uniform(Uniform),
+    Pair(Reg, Reg)
+}
+
+impl From<Reg> for CastTarget {
+    fn from(unit: Reg) -> CastTarget {
+        CastTarget::Uniform(Uniform::from(unit))
+    }
+}
+
+impl From<Uniform> for CastTarget {
+    fn from(uniform: Uniform) -> CastTarget {
+        CastTarget::Uniform(uniform)
+    }
+}
+
+impl CastTarget {
+    fn llvm_type(&self, ccx: &CrateContext) -> Type {
+        match *self {
+            CastTarget::Uniform(u) => u.llvm_type(ccx),
+            CastTarget::Pair(a, b) => {
+                Type::struct_(ccx, &[
+                    a.llvm_type(ccx),
+                    b.llvm_type(ccx)
+                ], false)
+            }
+        }
+    }
+}
 
 /// Information about how a specific C type
 /// should be passed to or returned from a function
 ///
 /// This is borrowed from clang's ABIInfo.h
 #[derive(Clone, Copy, Debug)]
-pub struct ArgType {
+pub struct ArgType<'tcx> {
     kind: ArgKind,
-    /// Original LLVM type
-    pub original_ty: Type,
-    /// Sizing LLVM type (pointers are opaque).
-    /// Unlike original_ty, this is guaranteed to be complete.
-    ///
-    /// For example, while we're computing the function pointer type in
-    /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`.
-    /// The field type will likely end up being `void(%Foo)*`, but we cannot
-    /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`,
-    /// until `%Foo` is completed by having all of its field types inserted,
-    /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers
-    /// with opaque ones, resulting in `{i8*}` for `Foo`.
-    /// ABI-specific logic can then look at the size, alignment and fields of
-    /// `{i8*}` in order to determine how the argument will be passed.
-    /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
-    /// pointer type, without ever having introspected it.
-    pub ty: Type,
-    /// Signedness for integer types, None for other types
-    pub signedness: Option<bool>,
+    pub layout: TyLayout<'tcx>,
     /// Coerced LLVM Type
     pub cast: Option<Type>,
     /// Dummy argument, which is emitted before the real argument
@@ -167,26 +428,24 @@ pub struct ArgType {
     pub attrs: ArgAttributes
 }
 
-impl ArgType {
-    fn new(original_ty: Type, ty: Type) -> ArgType {
+impl<'a, 'tcx> ArgType<'tcx> {
+    fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> {
         ArgType {
             kind: ArgKind::Direct,
-            original_ty: original_ty,
-            ty: ty,
-            signedness: None,
+            layout: layout,
             cast: None,
             pad: None,
             attrs: ArgAttributes::default()
         }
     }
 
-    pub fn make_indirect(&mut self, ccx: &CrateContext) {
+    pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) {
         assert_eq!(self.kind, ArgKind::Direct);
 
         // Wipe old attributes, likely not valid through indirection.
         self.attrs = ArgAttributes::default();
 
-        let llarg_sz = llsize_of_alloc(ccx, self.ty);
+        let llarg_sz = self.layout.size(ccx).bytes();
 
         // For non-immediate arguments the callee gets its own copy of
         // the value on the stack, so there are no aliases. It's also
@@ -205,17 +464,44 @@ pub fn ignore(&mut self) {
 
     pub fn extend_integer_width_to(&mut self, bits: u64) {
         // Only integers have signedness
-        if let Some(signed) = self.signedness {
-            if self.ty.int_width() < bits {
-                self.attrs.set(if signed {
-                    ArgAttribute::SExt
-                } else {
-                    ArgAttribute::ZExt
-                });
+        let (i, signed) = match *self.layout {
+            Layout::Scalar { value, .. } => {
+                match value {
+                    layout::Int(i) => {
+                        if self.layout.ty.is_integral() {
+                            (i, self.layout.ty.is_signed())
+                        } else {
+                            return;
+                        }
+                    }
+                    _ => return
+                }
             }
+
+            // Rust enum types that map onto C enums also need to follow
+            // the target ABI zero-/sign-extension rules.
+            Layout::CEnum { discr, signed, .. } => (discr, signed),
+
+            _ => return
+        };
+
+        if i.size().bits() < bits {
+            self.attrs.set(if signed {
+                ArgAttribute::SExt
+            } else {
+                ArgAttribute::ZExt
+            });
         }
     }
 
+    pub fn cast_to<T: Into<CastTarget>>(&mut self, ccx: &CrateContext, target: T) {
+        self.cast = Some(target.into().llvm_type(ccx));
+    }
+
+    pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) {
+        self.pad = Some(reg.llvm_type(ccx));
+    }
+
     pub fn is_indirect(&self) -> bool {
         self.kind == ArgKind::Indirect
     }
@@ -224,18 +510,24 @@ pub fn is_ignore(&self) -> bool {
         self.kind == ArgKind::Ignore
     }
 
+    /// Get the LLVM type for an lvalue of the original Rust type of
+    /// this argument/return, i.e. the result of `type_of::type_of`.
+    pub fn memory_ty(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
+        type_of::type_of(ccx, self.layout.ty)
+    }
+
     /// Store a direct/indirect value described by this ArgType into a
     /// lvalue for the original Rust type of this argument/return.
     /// Can be used for both storing formal arguments into Rust variables
     /// or results of call/invoke instructions into their destinations.
-    pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
+    pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) {
         if self.is_ignore() {
             return;
         }
         let ccx = bcx.ccx;
         if self.is_indirect() {
-            let llsz = llsize_of(ccx, self.ty);
-            let llalign = llalign_of_min(ccx, self.ty);
+            let llsz = C_uint(ccx, self.layout.size(ccx).bytes());
+            let llalign = self.layout.align(ccx).abi();
             base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
         } else if let Some(ty) = self.cast {
             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
@@ -243,8 +535,8 @@ pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
             let can_store_through_cast_ptr = false;
             if can_store_through_cast_ptr {
                 let cast_dst = bcx.pointercast(dst, ty.ptr_to());
-                let llalign = llalign_of_min(ccx, self.ty);
-                bcx.store(val, cast_dst, Some(llalign));
+                let llalign = self.layout.align(ccx).abi();
+                bcx.store(val, cast_dst, Some(llalign as u32));
             } else {
                 // The actual return type is a struct, but the ABI
                 // adaptation code has cast it into some scalar type.  The
@@ -271,21 +563,21 @@ pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
                 base::call_memcpy(bcx,
                                   bcx.pointercast(dst, Type::i8p(ccx)),
                                   bcx.pointercast(llscratch, Type::i8p(ccx)),
-                                  C_uint(ccx, llsize_of_alloc(ccx, self.ty)),
-                                  cmp::min(llalign_of_min(ccx, self.ty),
-                                           llalign_of_min(ccx, ty)) as u32);
+                                  C_uint(ccx, self.layout.size(ccx).bytes()),
+                                  cmp::min(self.layout.align(ccx).abi() as u32,
+                                           llalign_of_min(ccx, ty)));
 
                 base::Lifetime::End.call(bcx, llscratch);
             }
         } else {
-            if self.original_ty == Type::i1(ccx) {
+            if self.layout.ty == ccx.tcx().types.bool {
                 val = bcx.zext(val, Type::i8(ccx));
             }
             bcx.store(val, dst, None);
         }
     }
 
-    pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) {
+    pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: ValueRef) {
         if self.pad.is_some() {
             *idx += 1;
         }
@@ -304,30 +596,30 @@ pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) {
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
 #[derive(Clone, Debug)]
-pub struct FnType {
+pub struct FnType<'tcx> {
     /// The LLVM types of each argument.
-    pub args: Vec<ArgType>,
+    pub args: Vec<ArgType<'tcx>>,
 
     /// LLVM return type.
-    pub ret: ArgType,
+    pub ret: ArgType<'tcx>,
 
     pub variadic: bool,
 
     pub cconv: llvm::CallConv
 }
 
-impl FnType {
-    pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                         sig: ty::FnSig<'tcx>,
-                         extra_args: &[Ty<'tcx>]) -> FnType {
+impl<'a, 'tcx> FnType<'tcx> {
+    pub fn new(ccx: &CrateContext<'a, 'tcx>,
+               sig: ty::FnSig<'tcx>,
+               extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
-    pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                sig: ty::FnSig<'tcx>,
-                                extra_args: &[Ty<'tcx>]) -> FnType {
+    pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>,
+                      extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         // Don't pass the vtable, it's not an argument of the virtual fn.
         fn_ty.args[1].ignore();
@@ -335,9 +627,9 @@ pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         fn_ty
     }
 
-    fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            sig: ty::FnSig<'tcx>,
-                            extra_args: &[Ty<'tcx>]) -> FnType {
+    pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>,
+                      extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
         use self::Abi::*;
         let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic |
@@ -394,23 +686,11 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         };
 
         let arg_of = |ty: Ty<'tcx>, is_return: bool| {
+            let mut arg = ArgType::new(ccx.layout_of(ty));
             if ty.is_bool() {
-                let llty = Type::i1(ccx);
-                let mut arg = ArgType::new(llty, llty);
                 arg.attrs.set(ArgAttribute::ZExt);
-                arg
             } else {
-                let mut arg = ArgType::new(type_of::type_of(ccx, ty),
-                                           type_of::sizing_type_of(ccx, ty));
-                if ty.is_integral() {
-                    arg.signedness = Some(ty.is_signed());
-                }
-                // Rust enum types that map onto C enums also need to follow
-                // the target ABI zero-/sign-extension rules.
-                if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) {
-                    arg.signedness = Some(signed);
-                }
-                if llsize_of_alloc(ccx, arg.ty) == 0 {
+                if arg.layout.size(ccx).bytes() == 0 {
                     // For some forsaken reason, x86_64-pc-windows-gnu
                     // doesn't ignore zero-sized struct arguments.
                     // The same is true for s390x-unknown-linux-gnu.
@@ -419,8 +699,8 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                         arg.ignore();
                     }
                 }
-                arg
             }
+            arg
         };
 
         let ret_ty = sig.output();
@@ -439,14 +719,10 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             match ret_ty.sty {
                 // These are not really pointers but pairs, (pointer, len)
                 ty::TyRef(_, ty::TypeAndMut { ty, .. }) => {
-                    let llty = type_of::sizing_type_of(ccx, ty);
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    ret.attrs.set_dereferenceable(llsz);
+                    ret.attrs.set_dereferenceable(ccx.size_of(ty));
                 }
                 ty::TyAdt(def, _) if def.is_box() => {
-                    let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty());
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    ret.attrs.set_dereferenceable(llsz);
+                    ret.attrs.set_dereferenceable(ccx.size_of(ret_ty.boxed_ty()));
                 }
                 _ => {}
             }
@@ -495,13 +771,9 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         for ty in inputs.iter().chain(extra_args.iter()) {
             let mut arg = arg_of(ty, false);
 
-            if type_is_fat_ptr(ccx, ty) {
-                let original_tys = arg.original_ty.field_types();
-                let sizing_tys = arg.ty.field_types();
-                assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2));
-
-                let mut data = ArgType::new(original_tys[0], sizing_tys[0]);
-                let mut info = ArgType::new(original_tys[1], sizing_tys[1]);
+            if let ty::layout::FatPointer { .. } = *arg.layout {
+                let mut data = ArgType::new(arg.layout.field(ccx, 0));
+                let mut info = ArgType::new(arg.layout.field(ccx, 1));
 
                 if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
                     data.attrs.set(ArgAttribute::NonNull);
@@ -517,9 +789,7 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 args.push(info);
             } else {
                 if let Some(inner) = rust_ptr_attrs(ty, &mut arg) {
-                    let llty = type_of::sizing_type_of(ccx, inner);
-                    let llsz = llsize_of_alloc(ccx, llty);
-                    arg.attrs.set_dereferenceable(llsz);
+                    arg.attrs.set_dereferenceable(ccx.size_of(inner));
                 }
                 args.push(arg);
             }
@@ -533,43 +803,51 @@ fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
     }
 
-    fn adjust_for_abi<'a, 'tcx>(&mut self,
-                                ccx: &CrateContext<'a, 'tcx>,
-                                sig: ty::FnSig<'tcx>) {
+    fn adjust_for_abi(&mut self,
+                      ccx: &CrateContext<'a, 'tcx>,
+                      sig: ty::FnSig<'tcx>) {
         let abi = sig.abi;
         if abi == Abi::Unadjusted { return }
 
         if abi == Abi::Rust || abi == Abi::RustCall ||
            abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            let fixup = |arg: &mut ArgType| {
-                let mut llty = arg.ty;
-
-                // Replace newtypes with their inner-most type.
-                while llty.kind() == llvm::TypeKind::Struct {
-                    let inner = llty.field_types();
-                    if inner.len() != 1 {
-                        break;
-                    }
-                    llty = inner[0];
+            let fixup = |arg: &mut ArgType<'tcx>| {
+                if !arg.layout.is_aggregate() {
+                    return;
                 }
 
-                if !llty.is_aggregate() {
-                    // Scalars and vectors, always immediate.
-                    if llty != arg.ty {
+                let size = arg.layout.size(ccx);
+
+                if let Some(unit) = arg.layout.homogenous_aggregate(ccx) {
+                    // Replace newtypes with their inner-most type.
+                    if unit.size == size {
                         // Needs a cast as we've unpacked a newtype.
-                        arg.cast = Some(llty);
+                        arg.cast_to(ccx, unit);
+                        return;
+                    }
+
+                    // Pairs of floats.
+                    if unit.kind == RegKind::Float {
+                        if unit.size.checked_mul(2, ccx) == Some(size) {
+                            // FIXME(eddyb) This should be using Uniform instead of a pair,
+                            // but the resulting [2 x float/double] breaks emscripten.
+                            // See https://github.com/kripken/emscripten-fastcomp/issues/178.
+                            arg.cast_to(ccx, CastTarget::Pair(unit, unit));
+                            return;
+                        }
                     }
-                    return;
                 }
 
-                let size = llsize_of_alloc(ccx, llty);
-                if size > llsize_of_alloc(ccx, ccx.int_type()) {
+                if size > layout::Pointer.size(ccx) {
                     arg.make_indirect(ccx);
-                } else if size > 0 {
+                } else {
                     // We want to pass small aggregates as immediates, but using
                     // a LLVM aggregate type for this leads to bad optimizations,
                     // so we pick an appropriately sized integer type instead.
-                    arg.cast = Some(Type::ix(ccx, size * 8));
+                    arg.cast_to(ccx, Reg {
+                        kind: RegKind::Integer,
+                        size
+                    });
                 }
             };
             // Fat pointers are returned by-value.
@@ -605,14 +883,7 @@ fn adjust_for_abi<'a, 'tcx>(&mut self,
                 cabi_x86_64::compute_abi_info(ccx, self);
             },
             "aarch64" => cabi_aarch64::compute_abi_info(ccx, self),
-            "arm" => {
-                let flavor = if ccx.sess().target.target.target_os == "ios" {
-                    cabi_arm::Flavor::Ios
-                } else {
-                    cabi_arm::Flavor::General
-                };
-                cabi_arm::compute_abi_info(ccx, self, flavor);
-            },
+            "arm" => cabi_arm::compute_abi_info(ccx, self),
             "mips" => cabi_mips::compute_abi_info(ccx, self),
             "mips64" => cabi_mips64::compute_abi_info(ccx, self),
             "powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
@@ -633,16 +904,18 @@ fn adjust_for_abi<'a, 'tcx>(&mut self,
         }
     }
 
-    pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
+    pub fn llvm_type(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
         let mut llargument_tys = Vec::new();
 
         let llreturn_ty = if self.ret.is_ignore() {
             Type::void(ccx)
         } else if self.ret.is_indirect() {
-            llargument_tys.push(self.ret.original_ty.ptr_to());
+            llargument_tys.push(self.ret.memory_ty(ccx).ptr_to());
             Type::void(ccx)
         } else {
-            self.ret.cast.unwrap_or(self.ret.original_ty)
+            self.ret.cast.unwrap_or_else(|| {
+                type_of::immediate_type_of(ccx, self.ret.layout.ty)
+            })
         };
 
         for arg in &self.args {
@@ -655,9 +928,11 @@ pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
             }
 
             let llarg_ty = if arg.is_indirect() {
-                arg.original_ty.ptr_to()
+                arg.memory_ty(ccx).ptr_to()
             } else {
-                arg.cast.unwrap_or(arg.original_ty)
+                arg.cast.unwrap_or_else(|| {
+                    type_of::immediate_type_of(ccx, arg.layout.ty)
+                })
             };
 
             llargument_tys.push(llarg_ty);
@@ -705,72 +980,6 @@ pub fn apply_attrs_callsite(&self, callsite: ValueRef) {
     }
 }
 
-pub fn align_up_to(off: usize, a: usize) -> usize {
-    return (off + a - 1) / a * a;
-}
-
-fn align(off: usize, ty: Type, pointer: usize) -> usize {
-    let a = ty_align(ty, pointer);
-    return align_up_to(off, a);
-}
-
-pub fn ty_align(ty: Type, pointer: usize) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => pointer,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt, pointer)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ty_align(elt, pointer) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-pub fn ty_size(ty: Type, pointer: usize) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => pointer,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| {
-                    align(s, *t, pointer) + ty_size(*t, pointer)
-                });
-                align(size, ty, pointer)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, pointer);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, pointer);
-            len * eltsz
-        },
-        _ => bug!("ty_size: unhandled type")
-    }
+pub fn align_up_to(off: u64, a: u64) -> u64 {
+    (off + a - 1) / a * a
 }
index 5c1ced573402e07d8314d0654ee458b6bbde3a18..0fe180253b5b89c14fad0a77d6d752dd10882567 100644 (file)
@@ -46,8 +46,8 @@
 use std;
 
 use llvm::{ValueRef, True, IntEQ, IntNE};
-use rustc::ty::layout;
-use rustc::ty::{self, Ty, AdtKind};
+use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
 use common::*;
 use builder::Builder;
 use base;
@@ -95,15 +95,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
     generic_type_of(cx, t, None, false, false)
 }
 
-
-// Pass dst=true if the type you are passing is a DST. Yes, we could figure
-// this out, but if you call this on an unsized type without realising it, you
-// are going to get the wrong type (it will not include the unsized parts of it).
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                t: Ty<'tcx>, dst: bool) -> Type {
-    generic_type_of(cx, t, None, true, dst)
-}
-
 pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     t: Ty<'tcx>, name: &str) -> Type {
     generic_type_of(cx, t, Some(name), false, false)
@@ -149,7 +140,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             };
             let nnty = monomorphize::field_ty(cx.tcx(), substs,
                 &def.variants[nndiscr as usize].fields[0]);
-            type_of::sizing_type_of(cx, nnty)
+            if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) {
+                Type::i8p(cx)
+            } else {
+                type_of::type_of(cx, nnty)
+            }
         }
         layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
             let fields = compute_fields(cx, t, nndiscr as usize, false);
@@ -181,10 +176,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        layout::Vector { element, count } => {
-            let elem_ty = Type::from_primitive(cx, element);
-            Type::vector(&elem_ty, count)
-        }
         layout::UntaggedUnion { ref variants, .. }=> {
             // Use alignment-sized ints to fill all the union storage.
             let size = variants.stride().bytes();
@@ -246,9 +237,8 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
     assert_eq!(size%align, 0);
     assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
     let align_units = size/align;
-    let dl = &cx.tcx().data_layout;
     let layout_align = layout::Align::from_bytes(align, align).unwrap();
-    if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) {
+    if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) {
         Type::array(&Type::from_integer(cx, ity), align_units)
     } else {
         Type::array(&Type::vector(&Type::i32(cx), align/4),
@@ -259,11 +249,10 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
 
 fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
                              variant: &layout::Struct,
-                             sizing: bool, dst: bool) -> Vec<Type> {
+                             sizing: bool, _dst: bool) -> Vec<Type> {
     let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
     if sizing {
-        fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty))
-            .map(|ty| type_of::sizing_type_of(cx, ty)).collect()
+        bug!()
     } else {
         fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
     }
@@ -285,11 +274,6 @@ pub fn trans_get_discr<'a, 'tcx>(
     cast_to: Option<Type>,
     range_assert: bool
 ) -> ValueRef {
-    let (def, substs) = match t.sty {
-        ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs),
-        _ => bug!("{} is not an enum", t)
-    };
-
     debug!("trans_get_discr t: {:?}", t);
     let l = bcx.ccx.layout_of(t);
 
@@ -297,19 +281,17 @@ pub fn trans_get_discr<'a, 'tcx>(
         layout::CEnum { discr, min, max, .. } => {
             load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert)
         }
-        layout::General { discr, .. } => {
+        layout::General { discr, ref variants, .. } => {
             let ptr = bcx.struct_gep(scrutinee, 0);
             load_discr(bcx, discr, ptr, alignment,
-                       0, def.variants.len() as u64 - 1,
+                       0, variants.len() as u64 - 1,
                        range_assert)
         }
         layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
         layout::RawNullablePointer { nndiscr, .. } => {
             let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
-            let llptrty = type_of::sizing_type_of(bcx.ccx,
-                monomorphize::field_ty(bcx.tcx(), substs,
-                &def.variants[nndiscr as usize].fields[0]));
-            bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty))
+            let discr = bcx.load(scrutinee, alignment.to_align());
+            bcx.icmp(cmp, discr, C_null(val_ty(discr)))
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
             struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment)
@@ -383,9 +365,8 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
             assert_eq!(to, Disr(0));
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
             if to.0 != nndiscr {
-                let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
+                let llptrty = val_ty(val).element_type();
                 bcx.store(C_null(llptrty), val, None);
             }
         }
index 12a1ffa2767255aa325b6f3eff380d6fad49ca44..66380079a8b29038538e18324455f68bce83deb4 100644 (file)
@@ -707,13 +707,16 @@ fn link_natively(sess: &Session,
                  outputs: &OutputFilenames,
                  tmpdir: &Path) {
     info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
+    let flavor = sess.linker_flavor();
 
     // The invocations of cc share some flags across platforms
     let (pname, mut cmd, extra) = get_linker(sess);
     cmd.env("PATH", command_path(sess, extra));
 
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
-    cmd.args(&sess.target.target.options.pre_link_args);
+    if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
+        cmd.args(args);
+    }
 
     let pre_link_objects = if crate_type == config::CrateTypeExecutable {
         &sess.target.target.options.pre_link_objects_exe
@@ -739,11 +742,15 @@ fn link_natively(sess: &Session,
                   objects, out_filename, outputs, trans);
         cmd = linker.finalize();
     }
-    cmd.args(&sess.target.target.options.late_link_args);
+    if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
+        cmd.args(args);
+    }
     for obj in &sess.target.target.options.post_link_objects {
         cmd.arg(root.join(obj));
     }
-    cmd.args(&sess.target.target.options.post_link_args);
+    if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
+        cmd.args(args);
+    }
 
     if sess.opts.debugging_opts.print_link_args {
         println!("{:?}", &cmd);
index a178d17a7c2d371f01e17ce87fc7cd22a41efab7..61c57f00de70d5b00c229933d4ff5148767e963b 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use std::collections::HashMap;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufWriter};
@@ -22,6 +22,7 @@
 use back::symbol_export::{self, ExportedSymbols};
 use middle::dependency_format::Linkage;
 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
+use rustc_back::LinkerFlavor;
 use session::Session;
 use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
 use serialize::{json, Encoder};
@@ -45,25 +46,39 @@ pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
     pub fn to_linker(&'a self,
                      cmd: Command,
                      sess: &'a Session) -> Box<Linker+'a> {
-        if sess.target.target.options.is_like_msvc {
-            Box::new(MsvcLinker {
-                cmd: cmd,
-                sess: sess,
-                info: self
-            }) as Box<Linker>
-        } else if sess.target.target.options.is_like_emscripten {
-            Box::new(EmLinker {
-                cmd: cmd,
-                sess: sess,
-                info: self
-            }) as Box<Linker>
-        } else {
-            Box::new(GnuLinker {
-                cmd: cmd,
-                sess: sess,
-                info: self,
-                hinted_static: false,
-            }) as Box<Linker>
+        match sess.linker_flavor() {
+            LinkerFlavor::Msvc => {
+                Box::new(MsvcLinker {
+                    cmd: cmd,
+                    sess: sess,
+                    info: self
+                }) as Box<Linker>
+            }
+            LinkerFlavor::Em =>  {
+                Box::new(EmLinker {
+                    cmd: cmd,
+                    sess: sess,
+                    info: self
+                }) as Box<Linker>
+            }
+            LinkerFlavor::Gcc =>  {
+                Box::new(GccLinker {
+                    cmd: cmd,
+                    sess: sess,
+                    info: self,
+                    hinted_static: false,
+                    is_ld: false,
+                }) as Box<Linker>
+            }
+            LinkerFlavor::Ld => {
+                Box::new(GccLinker {
+                    cmd: cmd,
+                    sess: sess,
+                    info: self,
+                    hinted_static: false,
+                    is_ld: true,
+                }) as Box<Linker>
+            }
         }
     }
 }
@@ -100,14 +115,32 @@ pub trait Linker {
     fn finalize(&mut self) -> Command;
 }
 
-pub struct GnuLinker<'a> {
+pub struct GccLinker<'a> {
     cmd: Command,
     sess: &'a Session,
     info: &'a LinkerInfo,
     hinted_static: bool, // Keeps track of the current hinting mode.
+    // Link as ld
+    is_ld: bool,
 }
 
-impl<'a> GnuLinker<'a> {
+impl<'a> GccLinker<'a> {
+    /// Argument that must be passed *directly* to the linker
+    ///
+    /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used
+    fn linker_arg<S>(&mut self, arg: S) -> &mut Self
+        where S: AsRef<OsStr>
+    {
+        if !self.is_ld {
+            let mut os = OsString::from("-Wl,");
+            os.push(arg.as_ref());
+            self.cmd.arg(os);
+        } else {
+            self.cmd.arg(arg);
+        }
+        self
+    }
+
     fn takes_hints(&self) -> bool {
         !self.sess.target.target.options.is_like_osx
     }
@@ -119,7 +152,7 @@ fn takes_hints(&self) -> bool {
     fn hint_static(&mut self) {
         if !self.takes_hints() { return }
         if !self.hinted_static {
-            self.cmd.arg("-Wl,-Bstatic");
+            self.linker_arg("-Bstatic");
             self.hinted_static = true;
         }
     }
@@ -127,13 +160,13 @@ fn hint_static(&mut self) {
     fn hint_dynamic(&mut self) {
         if !self.takes_hints() { return }
         if self.hinted_static {
-            self.cmd.arg("-Wl,-Bdynamic");
+            self.linker_arg("-Bdynamic");
             self.hinted_static = false;
         }
     }
 }
 
-impl<'a> Linker for GnuLinker<'a> {
+impl<'a> Linker for GccLinker<'a> {
     fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
     fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
     fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
@@ -164,27 +197,26 @@ fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target.target;
         if !target.options.is_like_osx {
-            self.cmd.arg("-Wl,--whole-archive")
-                    .arg("-l").arg(lib)
-                    .arg("-Wl,--no-whole-archive");
+            self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib);
+            self.linker_arg("--no-whole-archive");
         } else {
             // -force_load is the macOS equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
-            let mut v = OsString::from("-Wl,-force_load,");
+            let mut v = OsString::from("-force_load,");
             v.push(&archive::find_library(lib, search_path, &self.sess));
-            self.cmd.arg(&v);
+            self.linker_arg(&v);
         }
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
         self.hint_static();
         if self.sess.target.target.options.is_like_osx {
-            let mut v = OsString::from("-Wl,-force_load,");
+            let mut v = OsString::from("-force_load,");
             v.push(lib);
-            self.cmd.arg(&v);
+            self.linker_arg(&v);
         } else {
-            self.cmd.arg("-Wl,--whole-archive").arg(lib)
-                    .arg("-Wl,--no-whole-archive");
+            self.linker_arg("--whole-archive").cmd.arg(lib);
+            self.linker_arg("--no-whole-archive");
         }
     }
 
@@ -204,10 +236,10 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         // for partial linking when using multiple codegen units (-r).  So we
         // insert it here.
         if self.sess.target.target.options.is_like_osx {
-            self.cmd.arg("-Wl,-dead_strip");
+            self.linker_arg("-dead_strip");
         } else if self.sess.target.target.options.is_like_solaris {
-            self.cmd.arg("-Wl,-z");
-            self.cmd.arg("-Wl,ignore");
+            self.linker_arg("-z");
+            self.linker_arg("ignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
         // has already done the best it can do, and we also don't want to
@@ -215,7 +247,7 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
         } else if !keep_metadata {
-            self.cmd.arg("-Wl,--gc-sections");
+            self.linker_arg("--gc-sections");
         }
     }
 
@@ -226,7 +258,7 @@ fn optimize(&mut self) {
         // need a numeric argument, but other linkers do.
         if self.sess.opts.optimize == config::OptLevel::Default ||
            self.sess.opts.optimize == config::OptLevel::Aggressive {
-            self.cmd.arg("-Wl,-O1");
+            self.linker_arg("-O1");
         }
     }
 
@@ -235,13 +267,16 @@ fn debuginfo(&mut self) {
     }
 
     fn no_default_libraries(&mut self) {
-        self.cmd.arg("-nodefaultlibs");
+        if !self.is_ld {
+            self.cmd.arg("-nodefaultlibs");
+        }
     }
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.target.options.is_like_osx {
-            self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
+            self.cmd.arg("-dynamiclib");
+            self.linker_arg("-dylib");
 
             // Note that the `osx_rpath_install_name` option here is a hack
             // purely to support rustbuild right now, we should get a more
@@ -249,9 +284,9 @@ fn build_dylib(&mut self, out_filename: &Path) {
             // the right `-Wl,-install_name` with an `@rpath` in it.
             if self.sess.opts.cg.rpath ||
                self.sess.opts.debugging_opts.osx_rpath_install_name {
-                let mut v = OsString::from("-Wl,-install_name,@rpath/");
+                let mut v = OsString::from("-install_name,@rpath/");
                 v.push(out_filename.file_name().unwrap());
-                self.cmd.arg(&v);
+                self.linker_arg(&v);
             }
         } else {
             self.cmd.arg("-shared");
@@ -307,11 +342,20 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         }
 
         if self.sess.target.target.options.is_like_osx {
-            arg.push("-Wl,-exported_symbols_list,");
+            if !self.is_ld {
+                arg.push("-Wl,")
+            }
+            arg.push("-exported_symbols_list,");
         } else if self.sess.target.target.options.is_like_solaris {
-            arg.push("-Wl,-M,");
+            if !self.is_ld {
+                arg.push("-Wl,")
+            }
+            arg.push("-M,");
         } else {
-            arg.push("-Wl,--version-script=");
+            if !self.is_ld {
+                arg.push("-Wl,")
+            }
+            arg.push("--version-script=");
         }
 
         arg.push(&path);
@@ -319,7 +363,7 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
     }
 
     fn subsystem(&mut self, subsystem: &str) {
-        self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
+        self.linker_arg(&format!("--subsystem,{}", subsystem));
     }
 
     fn finalize(&mut self) -> Command {
index d204703b775983ec2b74f60407e796373cf357d7..574b345218be9def7543abb1534eb700aae1e23b 100644 (file)
@@ -59,7 +59,6 @@
 use debuginfo;
 use declare;
 use machine;
-use machine::llsize_of;
 use meth;
 use mir;
 use monomorphize::{self, Instance};
@@ -534,14 +533,13 @@ pub fn memcpy_ty<'a, 'tcx>(
 ) {
     let ccx = bcx.ccx;
 
-    if type_is_zero_size(ccx, t) {
+    let size = ccx.size_of(t);
+    if size == 0 {
         return;
     }
 
-    let llty = type_of::type_of(ccx, t);
-    let llsz = llsize_of(ccx, llty);
-    let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t));
-    call_memcpy(bcx, dst, src, llsz, llalign as u32);
+    let align = align.unwrap_or_else(|| ccx.align_of(t));
+    call_memcpy(bcx, dst, src, C_uint(ccx, size), align);
 }
 
 pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
@@ -1297,8 +1295,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         // (delay format until we actually need it)
         let record = |kind, opt_discr_size, variants| {
             let type_desc = format!("{:?}", ty);
-            let overall_size = layout.size(&tcx.data_layout);
-            let align = layout.align(&tcx.data_layout);
+            let overall_size = layout.size(tcx);
+            let align = layout.align(tcx);
             tcx.sess.code_stats.borrow_mut().record_type_size(kind,
                                                               type_desc,
                                                               align,
@@ -1334,8 +1332,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
                     session::FieldInfo {
                         name: field_name.to_string(),
                         offset: offset.bytes(),
-                        size: field_layout.size(&tcx.data_layout).bytes(),
-                        align: field_layout.align(&tcx.data_layout).abi(),
+                        size: field_layout.size(tcx).bytes(),
+                        align: field_layout.align(tcx).abi(),
                     }
                 }
             }
@@ -1345,8 +1343,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
             session::VariantInfo {
                 name: Some(name.to_string()),
                 kind: session::SizeKind::Exact,
-                align: value.align(&tcx.data_layout).abi(),
-                size: value.size(&tcx.data_layout).bytes(),
+                align: value.align(tcx).abi(),
+                size: value.size(tcx).bytes(),
                 fields: vec![],
             }
         };
index 59a84439950bad2876ab8a18dd216bdafcc02b82..c8c5af714d92a92c2e945ef9d73c181393a8fc28 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
-
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
-
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
-
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
 
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
-        }
-
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
+        // Ensure we have at most four uniquely addressable members.
+        if size > unit.size.checked_mul(4, ccx).unwrap() {
+            return None;
         }
-    }
 
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        Vector => match ty_size(ty) {
-            4|8 => Some((ty, 1)),
-            _   => None
-        },
-        _ => None
-    };
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 64 || size.bits() == 128
+        };
 
-    // Ensure we have at most four uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 4 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
         return;
     }
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(32);
         return;
     }
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(arg.ty);
-    if size <= 16 {
-        let llty = if size == 0 {
-            Type::array(&Type::i64(ccx), 0)
-        } else if size == 1 {
-            Type::i8(ccx)
-        } else if size == 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = arg.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        arg.cast = Some(llty);
+
+        arg.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     arg.make_indirect(ccx);
 }
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 85b26074bae6d4358758eaea18d7bd0f3a5ba427..7a91cad511d6d17bc7688a17c30f25787da2a7a3 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
 
-use std::cmp;
-
-pub enum Flavor {
-    General,
-    Ios
-}
-
-type TyAlignFn = fn(ty: Type) -> usize;
-
-fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
-    let a = align_fn(ty);
-    return align_up_to(off, a);
-}
-
-fn general_ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
-
-// For more information see:
-// ARMv7
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-//    /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html
-// ARMv6
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-//    /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
-fn ios_ty_align(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8),
-        Pointer => 4,
-        Float => 4,
-        Double => 4,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ios_ty_align(elt)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ios_ty_align(elt) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter()
-                                  .fold(0, |s, t| {
-                                      align(s, *t, align_fn) + ty_size(*t, align_fn)
-                                  });
-                align(size, ty, align_fn)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, align_fn);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt, align_fn);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
         return;
     }
-    let size = ty_size(ret.ty, align_fn);
-    if size <= 4 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 32 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
         } else {
-            Type::i32(ccx)
+            Reg::i32()
         };
-        ret.cast = Some(llty);
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(32);
         return;
     }
-    let align = align_fn(arg.ty);
-    let size = ty_size(arg.ty, align_fn);
-    let llty = if align <= 4 {
-        Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64)
-    } else {
-        Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64)
-    };
-    arg.cast = Some(llty);
+    let align = arg.layout.align(ccx).abi();
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
+        total
+    });
 }
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
-    let align_fn = match flavor {
-        Flavor::General => general_ty_align as TyAlignFn,
-        Flavor::Ios => ios_ty_align as TyAlignFn,
-    };
-
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
-        classify_ret_ty(ccx, &mut fty.ret, align_fn);
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        classify_arg_ty(ccx, arg, align_fn);
+        classify_arg_ty(ccx, arg);
     }
 }
index f410627400c34ec4c2b1018d4188cdb3da48c941..f05dda8bce21acf819212c5cb224df06bbad50e8 100644 (file)
@@ -8,10 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use llvm::{Struct, Array};
-use abi::{FnType, ArgType, ArgAttribute};
+use abi::{FnType, ArgType, ArgAttribute, LayoutExt, Uniform};
 use context::CrateContext;
 
 // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
 // See the https://github.com/kripken/emscripten-fastcomp-clang repository.
 // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    match ret.ty.kind() {
-        Struct => {
-            let field_types = ret.ty.field_types();
-            if field_types.len() == 1 {
-                ret.cast = Some(field_types[0]);
-            } else {
-                ret.make_indirect(ccx);
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() {
+        if let Some(unit) = ret.layout.homogenous_aggregate(ccx) {
+            let size = ret.layout.size(ccx);
+            if unit.size == size {
+                ret.cast_to(ccx, Uniform {
+                    unit,
+                    total: size
+                });
+                return;
             }
         }
-        Array => {
-            ret.make_indirect(ccx);
-        }
-        _ => {}
+
+        ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.is_aggregate() {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() {
         arg.make_indirect(ccx);
         arg.attrs.set(ArgAttribute::ByVal);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 25fe53e7ef40f88ab96ba44d3ed6198a9af6fd24..b7b60859d4a048b9f53e0952659bcc7c133948ee 100644 (file)
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
+        }
     } else {
         arg.extend_integer_width_to(32);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
 
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index e6b500c88dc7ac1be0916491e5afb0be7ecba08f..dff75e628de10270fa83b09c4c6da22281ea21d5 100644 (file)
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 8)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i64(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i64());
+        }
     } else {
         arg.extend_integer_width_to(64);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i64(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
 
-    let r = size % 64;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index aa90bb7ab753ad706b7f437f035bed2f1274fe7a..546bb5ad9b44ef39b140c81dea2d817d8b186aeb 100644 (file)
 // Reference: MSP430 Embedded Application Binary Interface
 // http://www.ti.com/lit/an/slaa534/slaa534.pdf
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 2)
-}
 
 // 3.5 Structures or Unions Passed and Returned by Reference
 //
@@ -29,23 +20,23 @@ fn ty_size(ty: Type) -> usize {
 // returned by reference. To pass a structure or union by reference, the caller
 // places its address in the appropriate location: either in a register or on
 // the stack, according to its position in the argument list. (..)"
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(16);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(16);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 5ece19f764a8ac2572f9161815e7f62a9040c22e..3873752b25470638b2456a276a4b784499a6713e 100644 (file)
 // Reference: PTX Writer's Guide to Interoperability
 // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(32);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(32);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 880c6cfd7a8ac24387c183f97ef9848bb577ec89..24bf4920c16c1277dd50435442a0ffbd9cef9e3a 100644 (file)
 // Reference: PTX Writer's Guide to Interoperability
 // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 8)
-}
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 {
         ret.make_indirect(ccx);
     } else {
         ret.extend_integer_width_to(64);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 {
         arg.make_indirect(ccx);
     } else {
         arg.extend_integer_width_to(64);
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 4e1d7a93378270dfb006d8113c1417ecad0dbfc0..f951ac76391f6614b0936f013bbf12a3bd9d87e8 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc::c_uint;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
 
 use std::cmp;
 
-fn ty_align(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_align(ty, 4)
-    }
-}
-
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 4)
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
 
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
+        }
     } else {
         arg.extend_integer_width_to(32);
     }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    };
-}
 
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
-
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
-        }
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index cdc7c1fd1afb379e937c3825853d832260e5fb9e..c4f8d0b4b963780f6192834ac9329608f4ab14bd 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME: The PowerPC64 ABI needs to zero or sign extend function
-// call parameters, but compute_abi_info() is passed LLVM types
-// which have no sign information.
-//
+// FIXME:
 // Alignment of 128 bit types is not currently handled, this will
 // need to be fixed when PowerPC vector support is added.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 8)
-    }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
 
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
-
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
-
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
+        // Ensure we have at most eight uniquely addressable members.
+        if size > unit.size.checked_mul(8, ccx).unwrap() {
+            return None;
         }
 
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
-        }
-    }
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 128
+        };
 
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        _ => None
-    };
-
-    // Ensure we have at most eight uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 8 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
         return;
     }
@@ -111,78 +53,52 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
         ret.make_indirect(ccx);
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
 
     ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(64);
         return;
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
 
-    arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let long_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(long_ty);
-        n -= 1;
-    }
-
-    let r = size % 64;
-    if r > 0 {
-        args.push(Type::ix(ccx, r as u64));
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: Reg::i64(),
+        total
+    });
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 5a666c6083d16f4649cc9292ea8f878a35aa3e2a..fedebea3f4c998ea177607167a3a83b2748ff0cb 100644 (file)
 // FIXME: The assumes we're using the non-vector ABI, i.e. compiling
 // for a pre-z13 machine or using -mno-vx.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg};
 use context::CrateContext;
-use type_::Type;
 
-use std::cmp;
+use rustc::ty::layout::{self, Layout, TyLayout};
 
-fn align(off: usize, ty: Type) -> usize {
-    let a = ty_align(ty);
-    return align_up_to(off, a);
-}
-
-fn ty_align(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 8,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt)
-        }
-        Vector => ty_size(ty),
-        _ => bug!("ty_align: unhandled type")
-    }
-}
-
-fn ty_size(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 8,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
-                align(size, ty)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() && ret.layout.size(ccx).bits() <= 64 {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if arg.ty.kind() == Struct {
-        fn is_single_fp_element(tys: &[Type]) -> bool {
-            if tys.len() != 1 {
-                return false;
-            }
-            match tys[0].kind() {
-                Float | Double => true,
-                Struct => is_single_fp_element(&tys[0].field_types()),
-                _ => false
-            }
-        }
-
-        if is_single_fp_element(&arg.ty.field_types()) {
-            match ty_size(arg.ty) {
-                4 => arg.cast = Some(Type::f32(ccx)),
-                8 => arg.cast = Some(Type::f64(ccx)),
-                _ => arg.make_indirect(ccx)
-            }
-        } else {
-            match ty_size(arg.ty) {
-                1 => arg.cast = Some(Type::i8(ccx)),
-                2 => arg.cast = Some(Type::i16(ccx)),
-                4 => arg.cast = Some(Type::i32(ccx)),
-                8 => arg.cast = Some(Type::i64(ccx)),
-                _ => arg.make_indirect(ccx)
+fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                  layout: TyLayout<'tcx>) -> bool {
+    match *layout {
+        Layout::Scalar { value: layout::F32, .. } |
+        Layout::Scalar { value: layout::F64, .. } => true,
+        Layout::Univariant { .. } => {
+            if layout.field_count() == 1 {
+                is_single_fp_element(ccx, layout.field(ccx, 0))
+            } else {
+                false
             }
         }
-        return;
+        _ => false
     }
+}
 
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    let size = arg.layout.size(ccx);
+    if !arg.layout.is_aggregate() && size.bits() <= 64 {
         arg.extend_integer_width_to(64);
-    } else {
-        arg.make_indirect(ccx);
+        return;
     }
-}
 
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => ty_size(ty) <= 8,
-        _ => false
+    if is_single_fp_element(ccx, arg.layout) {
+        match size.bytes() {
+            4 => arg.cast_to(ccx, Reg::f32()),
+            8 => arg.cast_to(ccx, Reg::f64()),
+            _ => arg.make_indirect(ccx)
+        }
+    } else {
+        match size.bytes() {
+            1 => arg.cast_to(ccx, Reg::i8()),
+            2 => arg.cast_to(ccx, Reg::i16()),
+            4 => arg.cast_to(ccx, Reg::i32()),
+            8 => arg.cast_to(ccx, Reg::i64()),
+            _ => arg.make_indirect(ccx)
+        }
     }
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index 25fe53e7ef40f88ab96ba44d3ed6198a9af6fd24..c17901e1adebc113aace587a507e7cf3044cc122 100644 (file)
@@ -8,94 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
 use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
 use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
-    abi::ty_align(ty, 4)
-}
 
-fn ty_size(ty: Type) -> usize {
-    abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(32);
     } else {
         ret.make_indirect(ccx);
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
-    let orig_offset = *offset;
-    let size = ty_size(arg.ty) * 8;
-    let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+    let size = arg.layout.size(ccx);
+    let mut align = arg.layout.align(ccx).abi();
     align = cmp::min(cmp::max(align, 4), 8);
-    *offset = align_up_to(*offset, align);
-    *offset += align_up_to(size, align * 8) / 8;
-
-    if !is_reg_ty(arg.ty) {
-        arg.cast = Some(struct_ty(ccx, arg.ty));
-        arg.pad = padding_ty(ccx, align, orig_offset);
-    } else {
-        arg.extend_integer_width_to(32);
-    }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    return match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double
-        | Vector => true,
-        _ => false
-    };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
-    if ((align - 1 ) & offset) > 0 {
-        Some(Type::i32(ccx))
-    } else {
-        None
-    }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let int_ty = Type::i32(ccx);
-    let mut args = Vec::new();
 
-    let mut n = size / 32;
-    while n > 0 {
-        args.push(int_ty);
-        n -= 1;
-    }
-
-    let r = size % 32;
-    if r > 0 {
-        unsafe {
-            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+    if arg.layout.is_aggregate() {
+        arg.cast_to(ccx, Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if ((align - 1) & *offset) > 0 {
+            arg.pad_with(ccx, Reg::i32());
         }
+    } else {
+        arg.extend_integer_width_to(32)
     }
 
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size.bytes(), align);
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index e675cca33d1be9576a0b5e009fb39a29f76137b0..b75fa97f948ecadfea7e2ee2c1af8f3faf825881 100644 (file)
 
 // FIXME: This needs an audit for correctness and completeness.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
 use context::CrateContext;
-use type_::Type;
 
-fn ty_size(ty: Type) -> usize {
-    if ty.kind() == Vector {
-        bug!("ty_size: unhandled type")
-    } else {
-        abi::ty_size(ty, 8)
-    }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
-    fn check_array(ty: Type) -> Option<(Type, u64)> {
-        let len = ty.array_length() as u64;
-        if len == 0 {
-            return None
-        }
-        let elt = ty.element_type();
-
-        // if our element is an HFA/HVA, so are we; multiply members by our len
-        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
-    }
-
-    fn check_struct(ty: Type) -> Option<(Type, u64)> {
-        let str_tys = ty.field_types();
-        if str_tys.len() == 0 {
-            return None
-        }
-
-        let mut prev_base_ty = None;
-        let mut members = 0;
-        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
-            match (prev_base_ty, opt_homog_agg) {
-                // field isn't itself an HFA, so we aren't either
-                (_, None) => return None,
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+                                     -> Option<Uniform> {
+    arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+        let size = arg.layout.size(ccx);
 
-                // first field - store its type and number of members
-                (None, Some((field_ty, field_members))) => {
-                    prev_base_ty = Some(field_ty);
-                    members = field_members;
-                },
-
-                // 2nd or later field - give up if it's a different type; otherwise incr. members
-                (Some(prev_ty), Some((field_ty, field_members))) => {
-                    if prev_ty != field_ty {
-                        return None;
-                    }
-                    members += field_members;
-                }
-            }
+        // Ensure we have at most eight uniquely addressable members.
+        if size > unit.size.checked_mul(8, ccx).unwrap() {
+            return None;
         }
 
-        // Because of previous checks, we know prev_base_ty is Some(...) because
-        //   1. str_tys has at least one element; and
-        //   2. prev_base_ty was filled in (or we would've returned early)
-        let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
-        // Ensure there is no padding.
-        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
-            Some((base_ty, members))
-        } else {
-            None
-        }
-    }
-
-    let homog_agg = match ty.kind() {
-        Float  => Some((ty, 1)),
-        Double => Some((ty, 1)),
-        Array  => check_array(ty),
-        Struct => check_struct(ty),
-        _ => None
-    };
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 128
+        };
 
-    // Ensure we have at most eight uniquely addressable members
-    homog_agg.and_then(|(base_ty, members)| {
-        if members > 0 && members <= 8 {
-            Some((base_ty, members))
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
         } else {
             None
         }
     })
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+    if !ret.layout.is_aggregate() {
         ret.extend_integer_width_to(64);
         return;
     }
 
-    // don't return aggregates in registers
-    ret.make_indirect(ccx);
-
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
-        ret.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+        ret.cast_to(ccx, uniform);
         return;
     }
-    let size = ty_size(ret.ty);
-    if size <= 16 {
-        let llty = if size <= 1 {
-            Type::i8(ccx)
-        } else if size <= 2 {
-            Type::i16(ccx)
-        } else if size <= 4 {
-            Type::i32(ccx)
-        } else if size <= 8 {
-            Type::i64(ccx)
+    let size = ret.layout.size(ccx);
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
         } else {
-            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+            Reg::i64()
         };
-        ret.cast = Some(llty);
+
+        ret.cast_to(ccx, Uniform {
+            unit,
+            total: size
+        });
         return;
     }
+
+    // don't return aggregates in registers
+    ret.make_indirect(ccx);
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
-    if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
         arg.extend_integer_width_to(64);
         return;
     }
 
-    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
-        arg.cast = Some(Type::array(&base_ty, members));
+    if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+        arg.cast_to(ccx, uniform);
         return;
     }
 
-    arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
-    match ty.kind() {
-        Integer
-        | Pointer
-        | Float
-        | Double => true,
-        _ => false
-    }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
-    let long_ty = Type::i64(ccx);
-    let mut args = Vec::new();
-
-    let mut n = size / 64;
-    while n > 0 {
-        args.push(long_ty);
-        n -= 1;
-    }
-
-    let r = size % 64;
-    if r > 0 {
-        args.push(Type::ix(ccx, r as u64));
-    }
-
-    args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
-    let size = ty_size(ty) * 8;
-    Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+    let total = arg.layout.size(ccx);
+    arg.cast_to(ccx, Uniform {
+        unit: Reg::i64(),
+        total
+    });
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
     if !fty.ret.is_ignore() {
         classify_ret_ty(ccx, &mut fty.ret);
     }
index fea005f3d77da388194cdaf7a9f4d1734b544dd0..9f5520dabe3349e14dbdffbfda4fdeac7998d187 100644 (file)
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::*;
-use abi::{ArgAttribute, FnType};
-use type_::Type;
-use super::common::*;
-use super::machine::*;
+use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
+use common::CrateContext;
 
 #[derive(PartialEq)]
 pub enum Flavor {
@@ -20,9 +17,11 @@ pub enum Flavor {
     Fastcall
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                  fty: &mut FnType<'tcx>,
+                                  flavor: Flavor) {
     if !fty.ret.is_ignore() {
-        if fty.ret.ty.kind() == Struct {
+        if fty.ret.layout.is_aggregate() {
             // Returning a structure. Most often, this will use
             // a hidden first argument. On some platforms, though,
             // small structs are returned as integers.
@@ -33,11 +32,12 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
             let t = &ccx.sess().target.target;
             if t.options.is_like_osx || t.options.is_like_windows
                 || t.options.is_like_openbsd {
-                match llsize_of_alloc(ccx, fty.ret.ty) {
-                    1 => fty.ret.cast = Some(Type::i8(ccx)),
-                    2 => fty.ret.cast = Some(Type::i16(ccx)),
-                    4 => fty.ret.cast = Some(Type::i32(ccx)),
-                    8 => fty.ret.cast = Some(Type::i64(ccx)),
+                let size = fty.ret.layout.size(ccx);
+                match size.bytes() {
+                    1 => fty.ret.cast_to(ccx, Reg::i8()),
+                    2 => fty.ret.cast_to(ccx, Reg::i16()),
+                    4 => fty.ret.cast_to(ccx, Reg::i32()),
+                    8 => fty.ret.cast_to(ccx, Reg::i64()),
                     _ => fty.ret.make_indirect(ccx)
                 }
             } else {
@@ -50,7 +50,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        if arg.ty.kind() == Struct {
+        if arg.layout.is_aggregate() {
             arg.make_indirect(ccx);
             arg.attrs.set(ArgAttribute::ByVal);
         } else {
@@ -73,12 +73,15 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
         for arg in &mut fty.args {
             if arg.is_ignore() || arg.is_indirect() { continue; }
 
-            if arg.ty.kind() == Float {
+            // At this point we know this must be a primitive of sorts.
+            let unit = arg.layout.homogenous_aggregate(ccx).unwrap();
+            let size = arg.layout.size(ccx);
+            assert_eq!(unit.size, size);
+            if unit.kind == RegKind::Float {
                 continue;
             }
 
-            let size = llbitsize_of_real(ccx, arg.ty);
-            let size_in_regs = (size + 31) / 32;
+            let size_in_regs = (size.bits() + 31) / 32;
 
             if size_in_regs == 0 {
                 continue;
@@ -90,7 +93,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
 
             free_regs -= size_in_regs;
 
-            if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+            if size.bits() <= 32 && unit.kind == RegKind::Integer {
                 arg.attrs.set(ArgAttribute::InReg);
             }
 
index 7f2fdbf000b651fd62acfab2cb256881e55375a5..cbe170d85834cfa527dc845f877153c5dd157c89 100644 (file)
 // The classification code for the x86_64 ABI is taken from the clay language
 // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
 
-#![allow(non_upper_case_globals)]
-use self::RegClass::*;
-
-use llvm::{Integer, Pointer, Float, Double};
-use llvm::{Struct, Array, Vector};
-use abi::{self, ArgType, ArgAttribute, FnType};
+use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind};
 use context::CrateContext;
-use type_::Type;
-
-#[derive(Clone, Copy, PartialEq)]
-enum RegClass {
-    NoClass,
-    Int,
-    SSEFs,
-    SSEFv,
-    SSEDs,
-    SSEDv,
-    SSEInt(/* bitwidth */ u64),
-    /// Data that can appear in the upper half of an SSE register.
-    SSEUp,
-    X87,
-    X87Up,
-    ComplexX87,
-    Memory
-}
-
-trait TypeMethods {
-    fn is_reg_ty(&self) -> bool;
-}
-
-impl TypeMethods for Type {
-    fn is_reg_ty(&self) -> bool {
-        match self.kind() {
-            Integer | Pointer | Float | Double => true,
-            _ => false
-        }
-    }
-}
-
-impl RegClass {
-    fn is_sse(&self) -> bool {
-        match *self {
-            SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
-            _ => false
-        }
-    }
-}
-
-trait ClassList {
-    fn is_pass_byval(&self) -> bool;
-    fn is_ret_bysret(&self) -> bool;
-}
-
-impl ClassList for [RegClass] {
-    fn is_pass_byval(&self) -> bool {
-        if self.is_empty() { return false; }
-
-        let class = self[0];
-           class == Memory
-        || class == X87
-        || class == ComplexX87
-    }
 
-    fn is_ret_bysret(&self) -> bool {
-        if self.is_empty() { return false; }
+use rustc::ty::layout::{self, Layout, TyLayout, Size};
 
-        self[0] == Memory
-    }
+#[derive(Clone, Copy, PartialEq, Debug)]
+enum Class {
+    None,
+    Int,
+    Sse,
+    SseUp
 }
 
-fn classify_ty(ty: Type) -> Vec<RegClass> {
-    fn align(off: usize, ty: Type) -> usize {
-        let a = ty_align(ty);
-        return (off + a - 1) / a * a;
-    }
-
-    fn ty_align(ty: Type) -> usize {
-        abi::ty_align(ty, 8)
-    }
-
-    fn ty_size(ty: Type) -> usize {
-        abi::ty_size(ty, 8)
-    }
-
-    fn all_mem(cls: &mut [RegClass]) {
-        for elt in cls {
-            *elt = Memory;
-        }
-    }
-
-    fn unify(cls: &mut [RegClass],
-             i: usize,
-             newv: RegClass) {
-        if cls[i] == newv { return }
+#[derive(Clone, Copy, Debug)]
+struct Memory;
 
-        let to_write = match (cls[i], newv) {
-            (NoClass,     _) => newv,
-            (_,           NoClass) => return,
+// Currently supported vector size (AVX).
+const LARGEST_VECTOR_SIZE: usize = 256;
+const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
 
-            (Memory,      _) |
-            (_,           Memory) => Memory,
+fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
+                          -> Result<[Class; MAX_EIGHTBYTES], Memory> {
+    fn unify(cls: &mut [Class],
+             off: u64,
+             c: Class) {
+        let i = (off / 8) as usize;
+        let to_write = match (cls[i], c) {
+            (Class::None, _) => c,
+            (_, Class::None) => return,
 
-            (Int,         _) |
-            (_,           Int) => Int,
+            (Class::Int, _) |
+            (_, Class::Int) => Class::Int,
 
-            (X87,         _) |
-            (X87Up,       _) |
-            (ComplexX87,  _) |
-            (_,           X87) |
-            (_,           X87Up) |
-            (_,           ComplexX87) => Memory,
+            (Class::Sse, _) |
+            (_, Class::Sse) => Class::Sse,
 
-            (SSEFv,       SSEUp) |
-            (SSEFs,       SSEUp) |
-            (SSEDv,       SSEUp) |
-            (SSEDs,       SSEUp) |
-            (SSEInt(_),   SSEUp) => return,
-
-            (..) => newv
+            (Class::SseUp, Class::SseUp) => Class::SseUp
         };
         cls[i] = to_write;
     }
 
-    fn classify_struct(tys: &[Type],
-                       cls: &mut [RegClass],
-                       i: usize,
-                       off: usize,
-                       packed: bool) {
-        let mut field_off = off;
-        for ty in tys {
-            if !packed {
-                field_off = align(field_off, *ty);
+    fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                          layout: TyLayout<'tcx>,
+                          cls: &mut [Class],
+                          off: u64)
+                          -> Result<(), Memory> {
+        if off % layout.align(ccx).abi() != 0 {
+            if layout.size(ccx).bytes() > 0 {
+                return Err(Memory);
             }
-            classify(*ty, cls, i, field_off);
-            field_off += ty_size(*ty);
+            return Ok(());
         }
-    }
 
-    fn classify(ty: Type,
-                cls: &mut [RegClass], ix: usize,
-                off: usize) {
-        let t_align = ty_align(ty);
-        let t_size = ty_size(ty);
-
-        let misalign = off % t_align;
-        if misalign != 0 {
-            let mut i = off / 8;
-            let e = (off + t_size + 7) / 8;
-            while i < e {
-                unify(cls, ix + i, Memory);
-                i += 1;
+        match *layout {
+            Layout::Scalar { value, .. } |
+            Layout::RawNullablePointer { value, .. } => {
+                let reg = match value {
+                    layout::Int(_) |
+                    layout::Pointer => Class::Int,
+                    layout::F32 |
+                    layout::F64 => Class::Sse
+                };
+                unify(cls, off, reg);
             }
-            return;
-        }
 
-        match ty.kind() {
-            Integer |
-            Pointer => {
-                unify(cls, ix + off / 8, Int);
+            Layout::CEnum { .. } => {
+                unify(cls, off, Class::Int);
             }
-            Float => {
-                if off % 8 == 4 {
-                    unify(cls, ix + off / 8, SSEFv);
-                } else {
-                    unify(cls, ix + off / 8, SSEFs);
+
+            Layout::Vector { element, count } => {
+                unify(cls, off, Class::Sse);
+
+                // everything after the first one is the upper
+                // half of a register.
+                let eltsz = element.size(ccx).bytes();
+                for i in 1..count {
+                    unify(cls, off + i * eltsz, Class::SseUp);
                 }
             }
-            Double => {
-                unify(cls, ix + off / 8, SSEDs);
-            }
-            Struct => {
-                classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
-            }
-            Array => {
-                let len = ty.array_length();
-                let elt = ty.element_type();
-                let eltsz = ty_size(elt);
-                let mut i = 0;
-                while i < len {
-                    classify(elt, cls, ix, off + i * eltsz);
-                    i += 1;
+
+            Layout::Array { count, .. } => {
+                if count > 0 {
+                    let elt = layout.field(ccx, 0);
+                    let eltsz = elt.size(ccx).bytes();
+                    for i in 0..count {
+                        classify(ccx, elt, cls, off + i * eltsz)?;
+                    }
                 }
             }
-            Vector => {
-                let len = ty.vector_length();
-                let elt = ty.element_type();
-                let eltsz = ty_size(elt);
-                let mut reg = match elt.kind() {
-                    Integer => SSEInt(elt.int_width()),
-                    Float => SSEFv,
-                    Double => SSEDv,
-                    _ => bug!("classify: unhandled vector element type")
-                };
 
-                let mut i = 0;
-                while i < len {
-                    unify(cls, ix + (off + i * eltsz) / 8, reg);
+            Layout::Univariant { ref variant, .. } => {
+                for i in 0..layout.field_count() {
+                    let field_off = off + variant.offsets[i].bytes();
+                    classify(ccx, layout.field(ccx, i), cls, field_off)?;
+                }
+            }
 
-                    // everything after the first one is the upper
-                    // half of a register.
-                    reg = SSEUp;
-                    i += 1;
+            Layout::UntaggedUnion { .. } => {
+                for i in 0..layout.field_count() {
+                    classify(ccx, layout.field(ccx, i), cls, off)?;
                 }
             }
-            _ => bug!("classify: unhandled type")
+
+            Layout::FatPointer { .. } |
+            Layout::General { .. } |
+            Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
         }
+
+        Ok(())
+    }
+
+    let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize;
+    if n > MAX_EIGHTBYTES {
+        return Err(Memory);
     }
 
-    fn fixup(ty: Type, cls: &mut [RegClass]) {
+    let mut cls = [Class::None; MAX_EIGHTBYTES];
+    classify(ccx, arg.layout, &mut cls, 0)?;
+    if n > 2 {
+        if cls[0] != Class::Sse {
+            return Err(Memory);
+        }
+        if cls[1..n].iter().any(|&c| c != Class::SseUp) {
+            return Err(Memory);
+        }
+    } else {
         let mut i = 0;
-        let ty_kind = ty.kind();
-        let e = cls.len();
-        if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
-            if cls[i].is_sse() {
+        while i < n {
+            if cls[i] == Class::SseUp {
+                cls[i] = Class::Sse;
+            } else if cls[i] == Class::Sse {
                 i += 1;
-                while i < e {
-                    if cls[i] != SSEUp {
-                        all_mem(cls);
-                        return;
-                    }
-                    i += 1;
-                }
+                while i != n && cls[i] == Class::SseUp { i += 1; }
             } else {
-                all_mem(cls);
-                return
-            }
-        } else {
-            while i < e {
-                if cls[i] == Memory {
-                    all_mem(cls);
-                    return;
-                }
-                if cls[i] == X87Up {
-                    // for darwin
-                    // cls[i] = SSEDs;
-                    all_mem(cls);
-                    return;
-                }
-                if cls[i] == SSEUp {
-                    cls[i] = SSEDv;
-                } else if cls[i].is_sse() {
-                    i += 1;
-                    while i != e && cls[i] == SSEUp { i += 1; }
-                } else if cls[i] == X87 {
-                    i += 1;
-                    while i != e && cls[i] == X87Up { i += 1; }
-                } else {
-                    i += 1;
-                }
+                i += 1;
             }
         }
     }
 
-    let words = (ty_size(ty) + 7) / 8;
-    let mut cls = vec![NoClass; words];
-    if words > 4 {
-        all_mem(&mut cls);
-        return cls;
-    }
-    classify(ty, &mut cls, 0, 0);
-    fixup(ty, &mut cls);
-    return cls;
+    Ok(cls)
 }
 
-fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
-    fn llvec_len(cls: &[RegClass]) -> usize {
-        let mut len = 1;
-        for c in cls {
-            if *c != SSEUp {
-                break;
-            }
-            len += 1;
-        }
-        return len;
+fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
+    if *i >= cls.len() {
+        return None;
     }
 
-    let mut tys = Vec::new();
-    let mut i = 0;
-    let e = cls.len();
-    while i < e {
-        match cls[i] {
-            Int => {
-                tys.push(Type::i64(ccx));
-            }
-            SSEFv | SSEDv | SSEInt(_) => {
-                let (elts_per_word, elt_ty) = match cls[i] {
-                    SSEFv => (2, Type::f32(ccx)),
-                    SSEDv => (1, Type::f64(ccx)),
-                    SSEInt(bits) => {
-                        assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
-                                "llreg_ty: unsupported SSEInt width {}", bits);
-                        (64 / bits, Type::ix(ccx, bits))
+    match cls[*i] {
+        Class::None => None,
+        Class::Int => {
+            *i += 1;
+            Some(match size {
+                1 => Reg::i8(),
+                2 => Reg::i16(),
+                3 |
+                4 => Reg::i32(),
+                _ => Reg::i64()
+            })
+        }
+        Class::Sse => {
+            let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
+            *i += vec_len;
+            Some(match size {
+                4 => Reg::f32(),
+                8 => Reg::f64(),
+                _ => {
+                    Reg {
+                        kind: RegKind::Vector,
+                        size: Size::from_bytes(vec_len as u64 * 8)
                     }
-                    _ => bug!(),
-                };
-                let vec_len = llvec_len(&cls[i + 1..]);
-                let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
-                tys.push(vec_ty);
-                i += vec_len;
-                continue;
-            }
-            SSEFs => {
-                tys.push(Type::f32(ccx));
-            }
-            SSEDs => {
-                tys.push(Type::f64(ccx));
-            }
-            _ => bug!("llregtype: unhandled class")
+                }
+            })
         }
-        i += 1;
+        c => bug!("reg_component: unhandled class {:?}", c)
     }
-    if tys.len() == 1 && tys[0].kind() == Vector {
-        // if the type contains only a vector, pass it as that vector.
-        tys[0]
+}
+
+fn cast_target(cls: &[Class], size: u64) -> CastTarget {
+    let mut i = 0;
+    let lo = reg_component(cls, &mut i, size).unwrap();
+    let offset = i as u64 * 8;
+    let target = if size <= offset {
+        CastTarget::from(lo)
     } else {
-        Type::struct_(ccx, &tys, false)
-    }
+        let hi = reg_component(cls, &mut i, size - offset).unwrap();
+        CastTarget::Pair(lo, hi)
+    };
+    assert_eq!(reg_component(cls, &mut i, 0), None);
+    target
 }
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    fn x86_64_ty<F>(ccx: &CrateContext,
-                    arg: &mut ArgType,
-                    is_mem_cls: F,
-                    ind_attr: Option<ArgAttribute>)
-        where F: FnOnce(&[RegClass]) -> bool
-    {
-        if !arg.ty.is_reg_ty() {
-            let cls = classify_ty(arg.ty);
-            if is_mem_cls(&cls) {
-                arg.make_indirect(ccx);
-                if let Some(attr) = ind_attr {
-                    arg.attrs.set(attr);
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+    let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+    let mut sse_regs = 8; // XMM0-7
+
+    let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| {
+        let cls = classify_arg(ccx, arg);
+
+        let mut needed_int = 0;
+        let mut needed_sse = 0;
+        let in_mem = match cls {
+            Err(Memory) => true,
+            Ok(ref cls) if is_arg => {
+                for &c in cls {
+                    match c {
+                        Class::Int => needed_int += 1,
+                        Class::Sse => needed_sse += 1,
+                        _ => {}
+                    }
                 }
-            } else {
-                arg.cast = Some(llreg_ty(ccx, &cls));
+                arg.layout.is_aggregate() &&
+                    (int_regs < needed_int || sse_regs < needed_sse)
             }
-        } else {
-            arg.extend_integer_width_to(32);
-        }
-    }
+            Ok(_) => false
+        };
 
-    let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
-    let mut sse_regs = 8; // XMM0-7
+        if in_mem {
+            // `sret` / `byval` parameter thus one less integer register available
+            int_regs -= 1;
 
-    if !fty.ret.is_ignore() {
-        x86_64_ty(ccx, &mut fty.ret, |cls| {
-            if cls.is_ret_bysret() {
-                // `sret` parameter thus one less register available
-                int_regs -= 1;
-                true
+            arg.make_indirect(ccx);
+            if is_arg {
+                arg.attrs.set(ArgAttribute::ByVal);
+            }
+        } else {
+            // split into sized chunks passed individually
+            int_regs -= needed_int;
+            sse_regs -= needed_sse;
+
+            if arg.layout.is_aggregate() {
+                let size = arg.layout.size(ccx).bytes();
+                arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size))
             } else {
-                false
+                arg.extend_integer_width_to(32);
             }
-        }, None);
+        }
+    };
+
+    if !fty.ret.is_ignore() {
+        x86_64_ty(&mut fty.ret, false);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        x86_64_ty(ccx, arg, |cls| {
-            let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
-            let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
-            let in_mem = cls.is_pass_byval() ||
-                         int_regs < needed_int ||
-                         sse_regs < needed_sse;
-            if in_mem {
-                // `byval` parameter thus one less integer register available
-                int_regs -= 1;
-            } else {
-                // split into sized chunks passed individually
-                int_regs -= needed_int;
-                sse_regs -= needed_sse;
-            }
-            in_mem
-        }, Some(ArgAttribute::ByVal));
-
-        // An integer, pointer, double or float parameter
-        // thus the above closure passed to `x86_64_ty` won't
-        // get called.
-        match arg.ty.kind() {
-            Integer | Pointer => int_regs -= 1,
-            Double | Float => sse_regs -= 1,
-            _ => {}
-        }
+        x86_64_ty(arg, true);
     }
 }
index a849f38247380d1dd7e808a77aaa7d2b2bd2cacc..39e728d4e4f9b987bf4252031dbb2567b8665dbd 100644 (file)
@@ -8,30 +8,33 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::*;
-use super::common::*;
-use super::machine::*;
-use abi::{ArgType, FnType};
-use type_::Type;
+use abi::{ArgType, FnType, LayoutExt, Reg};
+use common::CrateContext;
+
+use rustc::ty::layout::Layout;
 
 // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    let fixup = |a: &mut ArgType| {
-        match a.ty.kind() {
-            Struct => match llsize_of_alloc(ccx, a.ty) {
-                          1 => a.cast = Some(Type::i8(ccx)),
-                          2 => a.cast = Some(Type::i16(ccx)),
-                          4 => a.cast = Some(Type::i32(ccx)),
-                          8 => a.cast = Some(Type::i64(ccx)),
-                          _ => a.make_indirect(ccx)
-                      },
-            Integer => match llsize_of_alloc(ccx, a.ty) {
-                           1 ... 8 => a.extend_integer_width_to(32),
-                           16 => a.make_indirect(ccx),
-                           _ => bug!(),
-            },
-            _ => (),
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+    let fixup = |a: &mut ArgType<'tcx>| {
+        let size = a.layout.size(ccx);
+        if a.layout.is_aggregate() {
+            match size.bits() {
+                8 => a.cast_to(ccx, Reg::i8()),
+                16 => a.cast_to(ccx, Reg::i16()),
+                32 => a.cast_to(ccx, Reg::i32()),
+                64 => a.cast_to(ccx, Reg::i64()),
+                _ => a.make_indirect(ccx)
+            };
+        } else {
+            if let Layout::Vector { .. } = *a.layout {
+                // FIXME(eddyb) there should be a size cap here
+                // (probably what clang calls "illegal vectors").
+            } else if size.bytes() > 8 {
+                a.make_indirect(ccx);
+            } else {
+                a.extend_integer_width_to(32);
+            }
         }
     };
 
index a0906bb02f5a32893db8c4fff5f754e6ec3b33c3..5d58c93538922ab6544adb417c5c1827b396551e 100644 (file)
@@ -27,7 +27,7 @@
 use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::hir;
 
@@ -63,7 +63,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
         Layout::UntaggedUnion { .. } |
         Layout::RawNullablePointer { .. } |
         Layout::StructWrappedNullablePointer { .. } => {
-            !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
+            !layout.is_unsized() && layout.size(ccx).bytes() == 0
         }
     }
 }
@@ -125,10 +125,8 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
 
 /// Identify types which have size zero at runtime.
 pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
-    use machine::llsize_of_alloc;
-    use type_of::sizing_type_of;
-    let llty = sizing_type_of(ccx, ty);
-    llsize_of_alloc(ccx, llty) == 0
+    let layout = ccx.layout_of(ty);
+    !layout.is_unsized() && layout.size(ccx).bytes() == 0
 }
 
 /*
index daf1a1ba95f9a175991e2877cf2c9e4d2b0d889e..6b6fa538dc03b655e72d8b3af5c663f1ea01e0c3 100644 (file)
@@ -255,7 +255,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             ccx.statics_to_rauw().borrow_mut().push((g, new_g));
             new_g
         };
-        llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
+        llvm::LLVMSetAlignment(g, ccx.align_of(ty));
         llvm::LLVMSetInitializer(g, v);
 
         // As an optimization, all shared statics which do not have interior
index afb94f546abe894aeb9e001a8545e2bc51915803..98fbb64fd55407b467c2bf20dbfb85744b563bfe 100644 (file)
@@ -28,6 +28,7 @@
 use rustc_data_structures::base_n;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{LayoutTyper, TyLayout};
 use session::config::NoDebugInfo;
 use session::Session;
 use session::config;
@@ -828,18 +829,6 @@ pub fn enter_type_of(&self, ty: Ty<'tcx>) -> TypeOfDepthLock<'b, 'tcx> {
         TypeOfDepthLock(self.local())
     }
 
-    pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
-        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
-            ty.layout(&infcx).unwrap_or_else(|e| {
-                match e {
-                    ty::layout::LayoutError::SizeOverflow(_) =>
-                        self.sess().fatal(&e.to_string()),
-                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
-                }
-            })
-        })
-    }
-
     pub fn check_overflow(&self) -> bool {
         self.shared.check_overflow
     }
@@ -951,6 +940,54 @@ pub fn eh_unwind_resume(&self) -> ValueRef {
     }
 }
 
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> {
+    fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
+    fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+        &self.shared.tcx.data_layout
+    }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.shared.tcx
+    }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+    type TyLayout = TyLayout<'tcx>;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
+            infcx.layout_of(ty).unwrap_or_else(|e| {
+                match e {
+                    ty::layout::LayoutError::SizeOverflow(_) =>
+                        self.sess().fatal(&e.to_string()),
+                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
+                }
+            })
+        })
+    }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
+    type TyLayout = TyLayout<'tcx>;
+
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.shared.layout_of(ty)
+    }
+}
+
 pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
 
 impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> {
index 049178a2575f39d10c80b13cf485360c622e39f6..ccb693aa41f4c4a5e8ac78ad33b5d6a1d86e4046 100644 (file)
@@ -35,7 +35,8 @@
 use {type_of, machine, monomorphize};
 use common::{self, CrateContext};
 use type_::Type;
-use rustc::ty::{self, AdtKind, Ty, layout};
+use rustc::ty::{self, AdtKind, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
 use session::config;
 use util::nodemap::FxHashMap;
 use util::common::path2cstr;
@@ -900,7 +901,7 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
         let offsets = match *layout {
             layout::Univariant { ref variant, .. } => &variant.offsets,
             layout::Vector { element, count } => {
-                let element_size = element.size(&cx.tcx().data_layout).bytes();
+                let element_size = element.size(cx).bytes();
                 tmp = (0..count).
                   map(|i| layout::Size::from_bytes(i*element_size))
                   .collect::<Vec<layout::Size>>();
@@ -1564,7 +1565,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         enum_llvm_type,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type: enum_type,
-            type_rep: type_rep,
+            type_rep: type_rep.layout,
             discriminant_type_metadata: discriminant_type_metadata,
             containing_scope: containing_scope,
             file_metadata: file_metadata,
@@ -1772,7 +1773,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     let var_name = CString::new(var_name).unwrap();
     let linkage_name = CString::new(linkage_name).unwrap();
 
-    let global_align = type_of::align_of(cx, variable_type);
+    let global_align = cx.align_of(variable_type);
 
     unsafe {
         llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
index 8e86b50b3f7dd7c39e6c23a9df91ed679c64cfaf..1b7cf26853bc137ebf91a01268069818776ae93e 100644 (file)
@@ -449,7 +449,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         LocalVariable    |
         CapturedVariable => (0, DW_TAG_auto_variable)
     };
-    let align = ::type_of::align_of(cx, variable_type);
+    let align = cx.align_of(variable_type);
 
     let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
     match (variable_access, &[][..]) {
index 41a9ab2842dcd3e85694b6d25b73f43821fb8c58..59876a7f2a201da688fe23eda5f397852fd9ceb0 100644 (file)
 use llvm::{ValueRef};
 use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
 use common::*;
-use machine::*;
 use meth;
 use monomorphize;
-use type_of::{sizing_type_of, align_of};
 use value::Value;
 use builder::Builder;
 
@@ -49,7 +48,7 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>
             if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
                 scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
                     let layout = t.layout(&infcx).unwrap();
-                    if layout.size(&scx.tcx().data_layout).bytes() == 0 {
+                    if layout.size(scx).bytes() == 0 {
                         // `Box<ZeroSizeType>` does not allocate.
                         false
                     } else {
@@ -69,9 +68,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, Value(info));
     if bcx.ccx.shared().type_is_sized(t) {
-        let sizing_type = sizing_type_of(bcx.ccx, t);
-        let size = llsize_of_alloc(bcx.ccx, sizing_type);
-        let align = align_of(bcx.ccx, t);
+        let size = bcx.ccx.size_of(t);
+        let align = bcx.ccx.align_of(t);
         debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
                t, Value(info), size, align);
         let size = C_uint(bcx.ccx, size);
@@ -82,9 +80,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
         ty::TyAdt(def, substs) => {
             let ccx = bcx.ccx;
             // First get the size of all statically known fields.
-            // Don't use type_of::sizing_type_of because that expects t to be sized,
-            // and it also rounds up to alignment, which we want to avoid,
-            // as the unsized field's alignment could be smaller.
+            // Don't use size_of because it also rounds up to alignment, which we
+            // want to avoid, as the unsized field's alignment could be smaller.
             assert!(!t.is_simd());
             let layout = ccx.layout_of(t);
             debug!("DST {} layout: {:?}", t, layout);
@@ -154,14 +151,11 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             (meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info))
         }
         ty::TySlice(_) | ty::TyStr => {
-            let unit_ty = t.sequence_element_type(bcx.tcx());
+            let unit = t.sequence_element_type(bcx.tcx());
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
-            let llunit_ty = sizing_type_of(bcx.ccx, unit_ty);
-            let unit_align = llalign_of_min(bcx.ccx, llunit_ty);
-            let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty);
-            (bcx.mul(info, C_uint(bcx.ccx, unit_size)),
-             C_uint(bcx.ccx, unit_align))
+            (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))),
+             C_uint(bcx.ccx, bcx.ccx.align_of(unit)))
         }
         _ => bug!("Unexpected unsized type, found {}", t)
     }
index 762bf8592ffccf83049d8804013b8d00f437141d..7077eade61182af2387119e8dd0801d8e3b48062 100644 (file)
@@ -16,7 +16,7 @@
 use llvm::{ValueRef};
 use abi::{Abi, FnType};
 use adt;
-use mir::lvalue::LvalueRef;
+use mir::lvalue::{LvalueRef, Alignment};
 use base::*;
 use common::*;
 use declare;
@@ -36,8 +36,6 @@
 use std::cmp::Ordering;
 use std::iter;
 
-use mir::lvalue::Alignment;
-
 fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     let llvm_name = match name {
         "sqrtf32" => "llvm.sqrt.f32",
@@ -151,7 +149,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         }
         "min_align_of" => {
             let tp_ty = substs.type_at(0);
-            C_uint(ccx, type_of::align_of(ccx, tp_ty))
+            C_uint(ccx, ccx.align_of(tp_ty))
         }
         "min_align_of_val" => {
             let tp_ty = substs.type_at(0);
@@ -160,7 +158,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
-                C_uint(ccx, type_of::align_of(ccx, tp_ty))
+                C_uint(ccx, ccx.align_of(tp_ty))
             }
         }
         "pref_align_of" => {
@@ -188,7 +186,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             C_nil(ccx)
         }
         // Effectively no-ops
-        "uninit" | "forget" => {
+        "uninit" => {
             C_nil(ccx)
         }
         "needs_drop" => {
@@ -234,7 +232,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             }
             let load = bcx.volatile_load(ptr);
             unsafe {
-                llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
+                llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty));
             }
             to_immediate(bcx, load, tp_ty)
         },
@@ -252,7 +250,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
                 let store = bcx.volatile_store(val, ptr);
                 unsafe {
-                    llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
+                    llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty));
                 }
             }
             C_nil(ccx)
@@ -622,7 +620,10 @@ fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
                     for i in 0..elems.len() {
                         let val = bcx.extract_value(val, i);
-                        bcx.store(val, bcx.struct_gep(llresult, i), None);
+                        let lval = LvalueRef::new_sized_ty(llresult, ret_ty,
+                                                           Alignment::AbiAligned);
+                        let (dest, align) = lval.trans_field_ptr(bcx, i);
+                        bcx.store(val, dest, align.to_align());
                     }
                     C_nil(ccx)
                 }
@@ -634,7 +635,7 @@ fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
         if let Some(ty) = fn_ty.ret.cast {
             let ptr = bcx.pointercast(llresult, ty.ptr_to());
-            bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
+            bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
         } else {
             store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty);
         }
@@ -651,7 +652,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                             -> ValueRef {
     let ccx = bcx.ccx;
     let lltp_ty = type_of::type_of(ccx, tp_ty);
-    let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
+    let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
     let size = machine::llsize_of(ccx, lltp_ty);
     let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
 
@@ -685,7 +686,7 @@ fn memset_intrinsic<'a, 'tcx>(
     count: ValueRef
 ) -> ValueRef {
     let ccx = bcx.ccx;
-    let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
+    let align = C_i32(ccx, ccx.align_of(ty) as i32);
     let lltp_ty = type_of::type_of(ccx, ty);
     let size = machine::llsize_of(ccx, lltp_ty);
     let dst = bcx.pointercast(dst, Type::i8p(ccx));
index 75ab407614050eab3e187c868b020627569245cf..f5f924178589a04d2d0efe8b1fcd9d1384d1ce84 100644 (file)
@@ -17,7 +17,6 @@
 use machine;
 use monomorphize;
 use type_::Type;
-use type_of::*;
 use value::Value;
 use rustc::ty;
 
@@ -80,14 +79,10 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Not in the cache. Build it.
     let nullptr = C_null(Type::nil(ccx).ptr_to());
 
-    let size_ty = sizing_type_of(ccx, ty);
-    let size = machine::llsize_of_alloc(ccx, size_ty);
-    let align = align_of(ccx, ty);
-
     let mut components: Vec<_> = [
         callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
-        C_uint(ccx, size),
-        C_uint(ccx, align)
+        C_uint(ccx, ccx.size_of(ty)),
+        C_uint(ccx, ccx.align_of(ty))
     ].iter().cloned().collect();
 
     if let Some(trait_ref) = trait_ref {
index d69f31a45048d48721e669e0c9af3cfcd56bb18d..caec4789eddce310a244e9c36ddf16eaa1138342 100644 (file)
@@ -12,7 +12,8 @@
 use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
 use rustc::middle::const_val::ConstInt;
-use rustc::ty::{self, layout, TypeFoldable};
+use rustc::ty::{self, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
 use base::{self, Lifetime};
@@ -24,8 +25,8 @@
 use machine::llalign_of_min;
 use meth;
 use monomorphize;
+use type_of;
 use tvec;
-use type_of::{self, align_of};
 use type_::Type;
 
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -177,7 +178,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     };
                     let llslot = match op.val {
                         Immediate(_) | Pair(..) => {
-                            let llscratch = bcx.alloca(ret.original_ty, "ret");
+                            let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret");
                             self.store_operand(&bcx, llscratch, None, op);
                             llscratch
                         }
@@ -189,7 +190,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     };
                     let load = bcx.load(
                         bcx.pointercast(llslot, cast_ty.ptr_to()),
-                        Some(llalign_of_min(bcx.ccx, ret.ty)));
+                        Some(ret.layout.align(bcx.ccx).abi() as u32));
                     load
                 } else {
                     let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
@@ -515,7 +516,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                             (llargs[0], &llargs[1..])
                         }
                         ReturnDest::Nothing => {
-                            (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
+                            (C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..])
                         }
                         ReturnDest::IndirectOperand(dst, _) |
                         ReturnDest::Store(dst) => (dst, &llargs[..]),
@@ -534,7 +535,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                             val: Ref(dst, Alignment::AbiAligned),
                             ty: sig.output(),
                         };
-                        self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
                     }
 
                     if let Some((_, target)) = *destination {
@@ -573,7 +574,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                             val: Immediate(invokeret),
                             ty: sig.output(),
                         };
-                        self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op);
                     }
                 } else {
                     let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
@@ -583,7 +584,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                             val: Immediate(llret),
                             ty: sig.output(),
                         };
-                        self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+                        self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
                         funclet_br(self, bcx, target);
                     } else {
                         bcx.unreachable();
@@ -597,7 +598,7 @@ fn trans_argument(&mut self,
                       bcx: &Builder<'a, 'tcx>,
                       op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
-                      fn_ty: &FnType,
+                      fn_ty: &FnType<'tcx>,
                       next_idx: &mut usize,
                       llfn: &mut Option<ValueRef>,
                       def: &Option<ty::InstanceDef<'tcx>>) {
@@ -640,7 +641,7 @@ fn trans_argument(&mut self,
         let (mut llval, align, by_ref) = match op.val {
             Immediate(_) | Pair(..) => {
                 if arg.is_indirect() || arg.cast.is_some() {
-                    let llscratch = bcx.alloca(arg.original_ty, "arg");
+                    let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
                     self.store_operand(bcx, llscratch, None, op);
                     (llscratch, Alignment::AbiAligned, true)
                 } else {
@@ -652,7 +653,7 @@ fn trans_argument(&mut self,
                 // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
                 // have scary latent bugs around.
 
-                let llscratch = bcx.alloca(arg.original_ty, "arg");
+                let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
                 base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
                 (llscratch, Alignment::AbiAligned, true)
             }
@@ -661,13 +662,13 @@ fn trans_argument(&mut self,
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if arg.original_ty == Type::i1(bcx.ccx) {
+            if arg.layout.ty == bcx.tcx().types.bool {
                 // We store bools as i8 so we need to truncate to i1.
                 llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
-                llval = bcx.trunc(llval, arg.original_ty);
+                llval = bcx.trunc(llval, Type::i1(bcx.ccx));
             } else if let Some(ty) = arg.cast {
                 llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()),
-                                 align.min_with(llalign_of_min(bcx.ccx, arg.ty)));
+                                 align.min_with(arg.layout.align(bcx.ccx).abi() as u32));
             } else {
                 llval = bcx.load(llval, align.to_align());
             }
@@ -680,7 +681,7 @@ fn trans_arguments_untupled(&mut self,
                                 bcx: &Builder<'a, 'tcx>,
                                 operand: &mir::Operand<'tcx>,
                                 llargs: &mut Vec<ValueRef>,
-                                fn_ty: &FnType,
+                                fn_ty: &FnType<'tcx>,
                                 next_idx: &mut usize,
                                 llfn: &mut Option<ValueRef>,
                                 def: &Option<ty::InstanceDef<'tcx>>) {
@@ -910,7 +911,7 @@ fn trans_transmute_into(&mut self, bcx: &Builder<'a, 'tcx>,
         let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
         let in_type = val.ty;
         let out_type = dst.ty.to_ty(bcx.tcx());;
-        let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
+        let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type));
         self.store_operand(bcx, cast_ptr, Some(llalign), val);
     }
 
@@ -919,7 +920,7 @@ fn trans_transmute_into(&mut self, bcx: &Builder<'a, 'tcx>,
     fn store_return(&mut self,
                     bcx: &Builder<'a, 'tcx>,
                     dest: ReturnDest,
-                    ret_ty: ArgType,
+                    ret_ty: &ArgType<'tcx>,
                     op: OperandRef<'tcx>) {
         use self::ReturnDest::*;
 
index dbd928194c0329834a14f47eb0a45ed12ae98d1d..4d5b691c86ebb514def7c8e559a6a2eb39f73b59 100644 (file)
@@ -18,7 +18,8 @@
 use rustc::infer::TransNormalize;
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
-use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -148,7 +149,7 @@ pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
         } else {
             // Otherwise, or if the value is not immediate, we create
             // a constant LLVM global and cast its address if necessary.
-            let align = type_of::align_of(ccx, self.ty);
+            let align = ccx.align_of(self.ty);
             let ptr = consts::addr_of(ccx, self.llval, align, "const");
             OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned)
         };
@@ -717,7 +718,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     Base::Value(llval) => {
                         // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
                         let align = if self.ccx.shared().type_is_sized(ty) {
-                            type_of::align_of(self.ccx, ty)
+                            self.ccx.align_of(ty)
                         } else {
                             self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
                         };
@@ -979,7 +980,6 @@ fn trans_const<'a, 'tcx>(
     vals: &[ValueRef]
 ) -> ValueRef {
     let l = ccx.layout_of(t);
-    let dl = &ccx.tcx().data_layout;
     let variant_index = match *kind {
         mir::AggregateKind::Adt(_, index, _, _) => index,
         _ => 0,
@@ -1002,7 +1002,7 @@ fn trans_const<'a, 'tcx>(
             let mut vals_with_discr = vec![lldiscr];
             vals_with_discr.extend_from_slice(vals);
             let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
-            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
+            let needed_padding = l.size(ccx).bytes() - variant.stride().bytes();
             if needed_padding > 0 {
                 contents.push(padding(ccx, needed_padding));
             }
@@ -1022,25 +1022,20 @@ fn trans_const<'a, 'tcx>(
             C_vector(vals)
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
             if variant_index as u64 == nndiscr {
                 assert_eq!(vals.len(), 1);
                 vals[0]
             } else {
-                C_null(type_of::sizing_type_of(ccx, nnty))
+                C_null(type_of::type_of(ccx, t))
             }
         }
         layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
             if variant_index as u64 == nndiscr {
                 C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
             } else {
-                let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
-                let vals = fields.iter().map(|&ty| {
-                    // Always use null even if it's not the `discrfield`th
-                    // field; see #8506.
-                    C_null(type_of::sizing_type_of(ccx, ty))
-                }).collect::<Vec<ValueRef>>();
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
+                // Always use null even if it's not the `discrfield`th
+                // field; see #8506.
+                C_null(type_of::type_of(ccx, t))
             }
         }
         _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
index dd8c1d0e1f0310d5b49d15b2593c03f0b454aacd..fc889604ab88ea900c50afd2ac1e24d04e8b4078 100644 (file)
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::ty::{self, layout, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
index 21bbbea77d442aa98f625df2ada73c179496bc46..f4c9a136ace3c9516e9857fb20651f1976455e3a 100644 (file)
@@ -11,7 +11,8 @@
 use libc::c_uint;
 use llvm::{self, ValueRef, BasicBlockRef};
 use llvm::debuginfo::DIScope;
-use rustc::ty::{self, layout};
+use rustc::ty;
+use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir::{self, Mir};
 use rustc::mir::tcx::LvalueTy;
 use rustc::ty::subst::Substs;
@@ -52,7 +53,7 @@ pub struct MirContext<'a, 'tcx:'a> {
 
     ccx: &'a CrateContext<'a, 'tcx>,
 
-    fn_ty: FnType,
+    fn_ty: FnType<'tcx>,
 
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
@@ -385,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
             let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index));
             for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
-                let dst = bcx.struct_gep(lvalue.llval, i);
+                let (dst, _) = lvalue.trans_field_ptr(bcx, i);
                 let arg = &mircx.fn_ty.args[idx];
                 idx += 1;
                 if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
@@ -454,6 +455,23 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 assert_eq!((meta.cast, meta.pad), (None, None));
                 let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
                 llarg_idx += 1;
+
+                // FIXME(eddyb) As we can't perfectly represent the data and/or
+                // vtable pointer in a fat pointers in Rust's typesystem, and
+                // because we split fat pointers into two ArgType's, they're
+                // not the right type so we have to cast them for now.
+                let pointee = match arg_ty.sty {
+                    ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
+                    ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => ty,
+                    ty::TyAdt(def, _) if def.is_box() => arg_ty.boxed_ty(),
+                    _ => bug!()
+                };
+                let data_llty = type_of::in_memory_type_of(bcx.ccx, pointee);
+                let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee);
+
+                let llarg = bcx.pointercast(llarg, data_llty.ptr_to());
+                let llmeta = bcx.pointercast(llmeta, meta_llty);
+
                 OperandValue::Pair(llarg, llmeta)
             } else {
                 OperandValue::Immediate(llarg)
index da24c03fdc2a01bebb03ba1f35b10afe7ca23c23..771a88238b2b73a66cbcdb319bebbf97e9ce5c98 100644 (file)
@@ -10,7 +10,7 @@
 
 use llvm::ValueRef;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
index d487aa6cd5be6f7d5e00dab89cc4683b80b2df9b..8f7cb914c47354294c7342dbe17b88e577c02eb2 100644 (file)
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
@@ -438,7 +438,7 @@ pub fn trans_rvalue_operand(&mut self,
                 let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
                 let llty = type_of::type_of(bcx.ccx, content_ty);
                 let llsize = machine::llsize_of(bcx.ccx, llty);
-                let align = type_of::align_of(bcx.ccx, content_ty);
+                let align = bcx.ccx.align_of(content_ty);
                 let llalign = C_uint(bcx.ccx, align);
                 let llty_ptr = llty.ptr_to();
                 let box_ty = bcx.tcx().mk_box(content_ty);
index a5722e6e520d0140df8f482b768f55517aa31fcb..d4ab6b0782855b7702c3b1fcfe030e4cf5aed512 100644 (file)
 use common::*;
 use machine;
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
 use trans_item::DefPathBasedNames;
 use type_::Type;
 
 use syntax::ast;
 
-
-// A "sizing type" is an LLVM type, the size and alignment of which are
-// guaranteed to be equivalent to what you would get out of `type_of()`. It's
-// useful because:
-//
-// (1) It may be cheaper to compute the sizing type than the full type if all
-//     you're interested in is the size and/or alignment;
-//
-// (2) It won't make any recursive calls to determine the structure of the
-//     type behind pointers. This can help prevent infinite loops for
-//     recursive types. For example, enum types rely on this behavior.
-
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
-    if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() {
-        return t;
-    }
-
-    debug!("sizing_type_of {:?}", t);
-    let _recursion_lock = cx.enter_type_of(t);
-
-    let ptr_sizing_ty = |ty: Ty<'tcx>| {
-        if cx.shared().type_is_sized(ty) {
-            Type::i8p(cx)
-        } else {
-            Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
-        }
-    };
-    let llsizingty = match t.sty {
-        _ if !cx.shared().type_is_sized(t) => {
-            Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
-        }
-
-        ty::TyBool => Type::bool(cx),
-        ty::TyChar => Type::char(cx),
-        ty::TyInt(t) => Type::int_from_ty(cx, t),
-        ty::TyUint(t) => Type::uint_from_ty(cx, t),
-        ty::TyFloat(t) => Type::float_from_ty(cx, t),
-        ty::TyNever => Type::nil(cx),
-
-        ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
-        ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
-            ptr_sizing_ty(ty)
-        }
-        ty::TyAdt(def, _) if def.is_box() => {
-            ptr_sizing_ty(t.boxed_ty())
-        }
-
-        ty::TyFnDef(..) => Type::nil(cx),
-        ty::TyFnPtr(_) => Type::i8p(cx),
-
-        ty::TyArray(ty, size) => {
-            let llty = sizing_type_of(cx, ty);
-            let size = size as u64;
-            Type::array(&llty, size)
-        }
-
-        ty::TyTuple(ref tys, _) if tys.is_empty() => {
-            Type::nil(cx)
-        }
-
-        ty::TyAdt(..) if t.is_simd() => {
-            let e = t.simd_type(cx.tcx());
-            if !e.is_machine() {
-                cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
-                                          a non-machine element type `{}`",
-                                         t, e))
-            }
-            let llet = type_of(cx, e);
-            let n = t.simd_size(cx.tcx()) as u64;
-            Type::vector(&llet, n)
-        }
-
-        ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => {
-            adt::sizing_type_of(cx, t, false)
-        }
-
-        ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
-        ty::TyAnon(..) | ty::TyError => {
-            bug!("fictitious type {:?} in sizing_type_of()", t)
-        }
-        ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!()
-    };
-
-    debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
-
-    cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
-
-    // FIXME(eddyb) Temporary sanity check for ty::layout.
-    let layout = cx.layout_of(t);
-    if !cx.shared().type_is_sized(t) {
-        if !layout.is_unsized() {
-            bug!("layout should be unsized for type `{}` / {:#?}",
-                 t, layout);
-        }
-
-        // Unsized types get turned into a fat pointer for LLVM.
-        return llsizingty;
-    }
-
-    let r = layout.size(&cx.tcx().data_layout).bytes();
-    let l = machine::llsize_of_alloc(cx, llsizingty);
-    if r != l {
-        bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-             r, l, t, layout);
-    }
-
-    let r = layout.align(&cx.tcx().data_layout).abi();
-    let l = machine::llalign_of_min(cx, llsizingty) as u64;
-    if r != l {
-        bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-             r, l, t, layout);
-    }
-
-    llsizingty
-}
-
 pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
     match ty.sty {
         ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
@@ -147,7 +32,7 @@ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
     }
 }
 
-fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
+pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
     let unsized_part = ccx.tcx().struct_tail(ty);
     match unsized_part.sty {
         ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
@@ -196,7 +81,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
 /// of that field's type - this is useful for taking the address of
 /// that field and ensuring the struct has the right alignment.
 /// For the LLVM type of a value as a whole, see `type_of`.
-/// NB: If you update this, be sure to update `sizing_type_of()` as well.
 pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
     // Check the cache.
     if let Some(&llty) = cx.lltypes().borrow().get(&t) {
@@ -322,10 +206,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
     llty
 }
 
-pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
-                          -> machine::llalign {
-    let layout = cx.layout_of(t);
-    layout.align(&cx.tcx().data_layout).abi() as machine::llalign
+impl<'a, 'tcx> CrateContext<'a, 'tcx> {
+    pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
+        self.layout_of(ty).align(self).abi() as machine::llalign
+    }
+
+    pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
+        self.layout_of(ty).size(self).bytes() as machine::llsize
+    }
 }
 
 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
index 2861fd288326b001f639e03bbf4fd7bb7f61a140..cd58fcd4806da62d104e61679c7a9527ae71bad6 100644 (file)
@@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             "rustc_peek" => (1, vec![param(0)], param(0)),
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
-            "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
             "transmute" => (2, vec![ param(0) ], param(1)),
             "move_val_init" => {
                 (1,
index 9f2d02c14dde0a4bece13c75d1e2167685e9e403..ffef42bc3d27ce1fe398c0d5dee6386c427a79d5 100644 (file)
 /// with a space after it.
 #[derive(Copy, Clone)]
 pub struct ConstnessSpace(pub hir::Constness);
-/// Wrapper struct for properly emitting a method declaration.
-pub struct Method<'a>(pub &'a clean::FnDecl, pub usize);
 /// Similar to VisSpace, but used for mutability
 #[derive(Copy, Clone)]
 pub struct MutableSpace(pub clean::Mutability);
 /// Similar to VisSpace, but used for mutability
 #[derive(Copy, Clone)]
 pub struct RawMutableSpace(pub clean::Mutability);
-/// Wrapper struct for emitting a where clause from Generics.
-pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize);
 /// Wrapper struct for emitting type parameter bounds.
 pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
 /// Wrapper struct for emitting a comma-separated list of items
 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
 pub struct AbiSpace(pub Abi);
 
+/// Wrapper struct for properly emitting a method declaration.
+pub struct Method<'a> {
+    /// The declaration to emit.
+    pub decl: &'a clean::FnDecl,
+    /// The length of the function's "name", used to determine line-wrapping.
+    pub name_len: usize,
+    /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
+    pub indent: usize,
+}
+
+/// Wrapper struct for emitting a where clause from Generics.
+pub struct WhereClause<'a>{
+    /// The Generics from which to emit a where clause.
+    pub gens: &'a clean::Generics,
+    /// The number of spaces to indent each line with.
+    pub indent: usize,
+    /// Whether the where clause needs to add a comma and newline after the last bound.
+    pub end_newline: bool,
+}
+
 pub struct HRef<'a> {
     pub did: DefId,
     pub text: &'a str,
@@ -167,24 +183,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl<'a> fmt::Display for WhereClause<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let &WhereClause(gens, pad) = self;
+        let &WhereClause { gens, indent, end_newline } = self;
         if gens.where_predicates.is_empty() {
             return Ok(());
         }
         let mut clause = String::new();
         if f.alternate() {
-            clause.push_str(" where ");
+            clause.push_str(" where");
         } else {
-            clause.push_str(" <span class=\"where fmt-newline\">where ");
+            if end_newline {
+                clause.push_str(" <span class=\"where fmt-newline\">where");
+            } else {
+                clause.push_str(" <span class=\"where\">where");
+            }
         }
         for (i, pred) in gens.where_predicates.iter().enumerate() {
-            if i > 0 {
-                if f.alternate() {
-                    clause.push_str(", ");
-                } else {
-                    clause.push_str(",<br>");
-                }
+            if f.alternate() {
+                clause.push(' ');
+            } else {
+                clause.push_str("<br>");
             }
+
             match pred {
                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
                     let bounds = bounds;
@@ -213,21 +232,29 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                     }
                 }
             }
+
+            if i < gens.where_predicates.len() - 1 || end_newline {
+                clause.push(',');
+            }
         }
+
+        if end_newline {
+            //add a space so stripping <br> tags and breaking spaces still renders properly
+            if f.alternate() {
+                clause.push(' ');
+            } else {
+                clause.push_str("&nbsp;");
+            }
+        }
+
         if !f.alternate() {
             clause.push_str("</span>");
-            let plain = format!("{:#}", self);
-            if plain.len() + pad > 80 {
-                // break it onto its own line regardless, but make sure method impls and trait
-                // blocks keep their fixed padding (2 and 9, respectively)
-                let padding = if pad > 10 {
-                    repeat("&nbsp;").take(8).collect::<String>()
-                } else {
-                    repeat("&nbsp;").take(pad + 6).collect::<String>()
-                };
-                clause = clause.replace("<br>", &format!("<br>{}", padding));
-            } else {
-                clause = clause.replace("<br>", " ");
+            let padding = repeat("&nbsp;").take(indent + 4).collect::<String>();
+            clause = clause.replace("<br>", &format!("<br>{}", padding));
+            clause.insert_str(0, &repeat("&nbsp;").take(indent.saturating_sub(1))
+                                                  .collect::<String>());
+            if !end_newline {
+                clause.insert_str(0, "<br>");
             }
         }
         write!(f, "{}", clause)
@@ -838,43 +865,35 @@ fn fmt_impl(i: &clean::Impl,
             f: &mut fmt::Formatter,
             link_trait: bool,
             use_absolute: bool) -> fmt::Result {
-    let mut plain = String::new();
-
     if f.alternate() {
         write!(f, "impl{:#} ", i.generics)?;
     } else {
         write!(f, "impl{} ", i.generics)?;
     }
-    plain.push_str(&format!("impl{:#} ", i.generics));
 
     if let Some(ref ty) = i.trait_ {
         if i.polarity == Some(clean::ImplPolarity::Negative) {
             write!(f, "!")?;
-            plain.push_str("!");
         }
 
         if link_trait {
             fmt::Display::fmt(ty, f)?;
-            plain.push_str(&format!("{:#}", ty));
         } else {
             match *ty {
                 clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
                     let last = path.segments.last().unwrap();
                     fmt::Display::fmt(&last.name, f)?;
                     fmt::Display::fmt(&last.params, f)?;
-                    plain.push_str(&format!("{:#}{:#}", last.name, last.params));
                 }
                 _ => unreachable!(),
             }
         }
         write!(f, " for ")?;
-        plain.push_str(" for ");
     }
 
     fmt_type(&i.for_, f, use_absolute, true)?;
-    plain.push_str(&format!("{:#}", i.for_));
 
-    fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
+    fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
     Ok(())
 }
 
@@ -939,12 +958,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl<'a> fmt::Display for Method<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let decl = self.0;
-        let indent = self.1;
+        let &Method { decl, name_len, indent } = self;
         let amp = if f.alternate() { "&" } else { "&amp;" };
         let mut args = String::new();
         let mut args_plain = String::new();
         for (i, input) in decl.inputs.values.iter().enumerate() {
+            if i == 0 {
+                args.push_str("<br>");
+            }
+
             if let Some(selfty) = input.to_self() {
                 match selfty {
                     clean::SelfValue => {
@@ -970,7 +992,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 }
             } else {
                 if i > 0 {
-                    args.push_str("<br> ");
+                    args.push_str(" <br>");
                     args_plain.push_str(" ");
                 }
                 if !input.name.is_empty() {
@@ -986,8 +1008,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 args_plain.push_str(&format!("{:#}", input.type_));
             }
             if i + 1 < decl.inputs.values.len() {
-                args.push_str(",");
-                args_plain.push_str(",");
+                args.push(',');
+                args_plain.push(',');
             }
         }
 
@@ -1003,27 +1025,23 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             format!("{}", decl.output)
         };
 
-        let mut output: String;
-        let plain: String;
-        let pad = repeat(" ").take(indent).collect::<String>();
-        if arrow.is_empty() {
-            output = format!("({})", args);
-            plain = format!("{}({})", pad, args_plain);
+        let pad = repeat(" ").take(name_len).collect::<String>();
+        let plain = format!("{pad}({args}){arrow}",
+                        pad = pad,
+                        args = args_plain,
+                        arrow = arrow_plain);
+
+        let output = if plain.len() > 80 {
+            let full_pad = format!("<br>{}", repeat("&nbsp;").take(indent + 4).collect::<String>());
+            let close_pad = format!("<br>{}", repeat("&nbsp;").take(indent).collect::<String>());
+            format!("({args}{close}){arrow}",
+                    args = args.replace("<br>", &full_pad),
+                    close = close_pad,
+                    arrow = arrow)
         } else {
-            output = format!("({args})<br>{arrow}", args = args, arrow = arrow);
-            plain = format!("{pad}({args}){arrow}",
-                            pad = pad,
-                            args = args_plain,
-                            arrow = arrow_plain);
-        }
+            format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
+        };
 
-        if plain.len() > 80 {
-            let pad = repeat("&nbsp;").take(indent).collect::<String>();
-            let pad = format!("<br>{}", pad);
-            output = output.replace("<br>", &pad);
-        } else {
-            output = output.replace("<br>", "");
-        }
         if f.alternate() {
             write!(f, "{}", output.replace("<br>", "\n"))
         } else {
index 1e1202f04005cdd3ccdb0b3b15b484c39b868b1e..42a18345681f69eec08283610d5a21f0340db37e 100644 (file)
@@ -2016,13 +2016,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         UnstableFeatures::Allow => f.constness,
         _ => hir::Constness::NotConst
     };
-    let indent = format!("{}{}{}{:#}fn {}{:#}",
-                         VisSpace(&it.visibility),
-                         ConstnessSpace(vis_constness),
-                         UnsafetySpace(f.unsafety),
-                         AbiSpace(f.abi),
-                         it.name.as_ref().unwrap(),
-                         f.generics).len();
+    let name_len = format!("{}{}{}{:#}fn {}{:#}",
+                           VisSpace(&it.visibility),
+                           ConstnessSpace(vis_constness),
+                           UnsafetySpace(f.unsafety),
+                           AbiSpace(f.abi),
+                           it.name.as_ref().unwrap(),
+                           f.generics).len();
     write!(w, "<pre class='rust fn'>")?;
     render_attributes(w, it)?;
     write!(w, "{vis}{constness}{unsafety}{abi}fn \
@@ -2033,8 +2033,12 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
            abi = AbiSpace(f.abi),
            name = it.name.as_ref().unwrap(),
            generics = f.generics,
-           where_clause = WhereClause(&f.generics, 2),
-           decl = Method(&f.decl, indent))?;
+           where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
+           decl = Method {
+               decl: &f.decl,
+               name_len: name_len,
+               indent: 0,
+           })?;
     document(w, cx, it)
 }
 
@@ -2062,14 +2066,18 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     // Output the trait definition
     write!(w, "<pre class='rust trait'>")?;
     render_attributes(w, it)?;
-    write!(w, "{}{}trait {}{}{}{} ",
+    write!(w, "{}{}trait {}{}{}",
            VisSpace(&it.visibility),
            UnsafetySpace(t.unsafety),
            it.name.as_ref().unwrap(),
            t.generics,
-           bounds,
-           // Where clauses in traits are indented nine spaces, per rustdoc.css
-           WhereClause(&t.generics, 9))?;
+           bounds)?;
+
+    if !t.generics.where_predicates.is_empty() {
+        write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
+    } else {
+        write!(w, " ")?;
+    }
 
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
@@ -2108,7 +2116,14 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         for m in &provided {
             write!(w, "    ")?;
             render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
-            write!(w, " {{ ... }}\n")?;
+            match m.inner {
+                clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
+                    write!(w, ",\n    {{ ... }}\n")?;
+                },
+                _ => {
+                    write!(w, " {{ ... }}\n")?;
+                },
+            }
         }
         write!(w, "}}")?;
     }
@@ -2342,21 +2357,17 @@ fn method(w: &mut fmt::Formatter,
         } else {
             hir::Constness::NotConst
         };
-        let prefix = format!("{}{}{:#}fn {}{:#}",
-                             ConstnessSpace(vis_constness),
-                             UnsafetySpace(unsafety),
-                             AbiSpace(abi),
-                             name,
-                             *g);
-        let mut indent = prefix.len();
-        let where_indent = if parent == ItemType::Trait {
-            indent += 4;
-            8
-        } else if parent == ItemType::Impl {
-            2
+        let mut head_len = format!("{}{}{:#}fn {}{:#}",
+                                   ConstnessSpace(vis_constness),
+                                   UnsafetySpace(unsafety),
+                                   AbiSpace(abi),
+                                   name,
+                                   *g).len();
+        let (indent, end_newline) = if parent == ItemType::Trait {
+            head_len += 4;
+            (4, false)
         } else {
-            let prefix = prefix + &format!("{:#}", Method(d, indent));
-            prefix.lines().last().unwrap().len() + 1
+            (0, true)
         };
         write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
@@ -2366,8 +2377,16 @@ fn method(w: &mut fmt::Formatter,
                href = href,
                name = name,
                generics = *g,
-               decl = Method(d, indent),
-               where_clause = WhereClause(g, where_indent))
+               decl = Method {
+                   decl: d,
+                   name_len: head_len,
+                   indent: indent,
+               },
+               where_clause = WhereClause {
+                   gens: g,
+                   indent: indent,
+                   end_newline: end_newline,
+               })
     }
     match item.inner {
         clean::StrippedItem(..) => Ok(()),
@@ -2480,15 +2499,11 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
     write!(w, "<pre class='rust enum'>")?;
     render_attributes(w, it)?;
-    let padding = format!("{}enum {}{:#} ",
-                          VisSpace(&it.visibility),
-                          it.name.as_ref().unwrap(),
-                          e.generics).len();
     write!(w, "{}enum {}{}{}",
            VisSpace(&it.visibility),
            it.name.as_ref().unwrap(),
            e.generics,
-           WhereClause(&e.generics, padding))?;
+           WhereClause { gens: &e.generics, indent: 0, end_newline: true })?;
     if e.variants.is_empty() && !e.variants_stripped {
         write!(w, " {{}}")?;
     } else {
@@ -2662,23 +2677,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                  fields: &[clean::Item],
                  tab: &str,
                  structhead: bool) -> fmt::Result {
-    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"struct "} else {""},
            it.name.as_ref().unwrap())?;
-    plain.push_str(&format!("{}{}{}",
-                            VisSpace(&it.visibility),
-                            if structhead {"struct "} else {""},
-                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
-        plain.push_str(&format!("{:#}", g));
         write!(w, "{}", g)?
     }
     match ty {
         doctree::Plain => {
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g, plain.len() + 1))?
+                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
             }
             let mut has_visible_fields = false;
             write!(w, " {{")?;
@@ -2707,35 +2716,30 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
         }
         doctree::Tuple => {
             write!(w, "(")?;
-            plain.push_str("(");
             for (i, field) in fields.iter().enumerate() {
                 if i > 0 {
                     write!(w, ", ")?;
-                    plain.push_str(", ");
                 }
                 match field.inner {
                     clean::StrippedItem(box clean::StructFieldItem(..)) => {
-                        plain.push_str("_");
                         write!(w, "_")?
                     }
                     clean::StructFieldItem(ref ty) => {
-                        plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
                         write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
                     }
                     _ => unreachable!()
                 }
             }
             write!(w, ")")?;
-            plain.push_str(")");
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g, plain.len() + 1))?
+                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
             }
             write!(w, ";")?;
         }
         doctree::Unit => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g, plain.len() + 1))?
+                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
             }
             write!(w, ";")?;
         }
@@ -2748,19 +2752,13 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
                 fields: &[clean::Item],
                 tab: &str,
                 structhead: bool) -> fmt::Result {
-    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap())?;
-    plain.push_str(&format!("{}{}{}",
-                            VisSpace(&it.visibility),
-                            if structhead {"union "} else {""},
-                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
         write!(w, "{}", g)?;
-        plain.push_str(&format!("{:#}", g));
-        write!(w, "{}", WhereClause(g, plain.len() + 1))?;
+        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?;
     }
 
     write!(w, " {{\n{}", tab)?;
@@ -3059,13 +3057,12 @@ fn render_default_items(w: &mut fmt::Formatter,
 
 fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                 t: &clean::Typedef) -> fmt::Result {
-    let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len();
     write!(w, "<pre class='rust typedef'>")?;
     render_attributes(w, it)?;
     write!(w, "type {}{}{where_clause} = {type_};</pre>",
            it.name.as_ref().unwrap(),
            t.generics,
-           where_clause = WhereClause(&t.generics, indent),
+           where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
            type_ = t.type_)?;
 
     document(w, cx, it)
index 4edf6309346ac129e5870f7ccbbc21a9ce2235ec..ddaa00aa4fb1446c5da00c571e6b2a6e7635359c 100644 (file)
@@ -379,12 +379,6 @@ h4 > code, h3 > code, .invisible > code {
 .content .where.fmt-newline {
        display: block;
 }
-/* Bit of whitespace to indent it */
-.content .method .where::before,
-.content .fn .where::before,
-.content .where.fmt-newline::before {
-       content: '  ';
-}
 
 .content .methods > div { margin-left: 40px; }
 
@@ -399,11 +393,6 @@ h4 > code, h3 > code, .invisible > code {
        font-size: 90%;
 }
 
-/* Shift where in trait listing down a line */
-pre.trait .where::before {
-       content: '\a         ';
-}
-
 nav {
        border-bottom: 1px solid;
        padding-bottom: 10px;
@@ -772,4 +761,4 @@ span.since {
        nav.sub, .content .out-of-band, .collapse-toggle {
                display: none;
        }
-}
\ No newline at end of file
+}
index b36253862094f4acf1c6aff41f1c89dd23193edb..4e3781ecafab5b008c82c2c3d5562f6fd50bbb89 100644 (file)
@@ -27,7 +27,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use fmt;
-use mem;
 use ops::Range;
 use iter::FusedIterator;
 
@@ -599,12 +598,12 @@ fn eq_ignore_ascii_case(&self, other: &str) -> bool {
     }
 
     fn make_ascii_uppercase(&mut self) {
-        let me: &mut [u8] = unsafe { mem::transmute(self) };
+        let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_uppercase()
     }
 
     fn make_ascii_lowercase(&mut self) {
-        let me: &mut [u8] = unsafe { mem::transmute(self) };
+        let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_lowercase()
     }
 
index fc1b9a976322ea50e4580380368cd437a39bcc08..29f977ecd8c33101c655425c565e6c491a4cf969 100644 (file)
@@ -324,6 +324,12 @@ pub fn as_bytes_with_nul(&self) -> &[u8] {
         &self.inner
     }
 
+    /// Extracts a `CStr` slice containing the entire string.
+    #[unstable(feature = "as_c_str", issue = "40380")]
+    pub fn as_c_str(&self) -> &CStr {
+        &*self
+    }
+
     /// Converts this `CString` into a boxed `CStr`.
     #[unstable(feature = "into_boxed_c_str", issue = "40380")]
     pub fn into_boxed_c_str(self) -> Box<CStr> {
index 064144dcd68183b82bddb06d086d38ee658af447..6299a9070ae03bd22bc9f1e34e50fe6d70887288 100644 (file)
 #![feature(stmt_expr_attributes)]
 #![feature(str_char)]
 #![feature(str_internals)]
+#![feature(str_mut_extras)]
 #![feature(str_utf16)]
 #![feature(test, rustc_private)]
 #![feature(thread_local)]
index 8cfd8fcd8c680b166fa38c14a3facd402afbc484..3795c42f5efa12aa2f3b086b586f9a058fbb1aec 100644 (file)
@@ -233,8 +233,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A handle to a child process's stderr. This struct is used in the [`stderr`]
-/// field on [`Child`].
+/// A handle to a child process's stderr.
+///
+/// This struct is used in the [`stderr`] field on [`Child`].
 ///
 /// [`Child`]: struct.Child.html
 /// [`stderr`]: struct.Child.html#structfield.stderr
index 0da65a4f2e12f2c9ed8d256d583515612a888092..852675edc0238d60baa13047c9bc6df67acbc402 100644 (file)
@@ -436,81 +436,97 @@ unsafe impl<T: Send> Send for SyncSender<T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> !Sync for SyncSender<T> {}
 
-/// An error returned from the [`send`] function on channels.
+/// An error returned from the [`Sender::send`] or [`SyncSender::send`]
+/// function on **channel**s.
 ///
-/// A [`send`] operation can only fail if the receiving end of a channel is
+/// A **send** operation can only fail if the receiving end of a channel is
 /// disconnected, implying that the data could never be received. The error
 /// contains the data being sent as a payload so it can be recovered.
 ///
-/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+/// [`Sender::send`]: struct.Sender.html#method.send
+/// [`SyncSender::send`]: struct.SyncSender.html#method.send
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
 
 /// An error returned from the [`recv`] function on a [`Receiver`].
 ///
-/// The [`recv`] operation can only fail if the sending half of a channel is
-/// disconnected, implying that no further messages will ever be received.
+/// The [`recv`] operation can only fail if the sending half of a
+/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// messages will ever be received.
 ///
-/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Receiver`]: struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RecvError;
 
 /// This enumeration is the list of the possible reasons that [`try_recv`] could
-/// not return data when called.
+/// not return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
 ///
-/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv
+/// [`try_recv`]: struct.Receiver.html#method.try_recv
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum TryRecvError {
-    /// This channel is currently empty, but the sender(s) have not yet
+    /// This **channel** is currently empty, but the **Sender**(s) have not yet
     /// disconnected, so data may yet become available.
     #[stable(feature = "rust1", since = "1.0.0")]
     Empty,
 
-    /// This channel's sending half has become disconnected, and there will
-    /// never be any more data received on this channel
+    /// The **channel**'s sending half has become disconnected, and there will
+    /// never be any more data received on it.
     #[stable(feature = "rust1", since = "1.0.0")]
     Disconnected,
 }
 
-/// This enumeration is the list of possible errors that [`recv_timeout`] could
-/// not return data when called.
+/// This enumeration is the list of possible errors that made [`recv_timeout`]
+/// unable to return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
 ///
-/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout
+/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
 pub enum RecvTimeoutError {
-    /// This channel is currently empty, but the sender(s) have not yet
+    /// This **channel** is currently empty, but the **Sender**(s) have not yet
     /// disconnected, so data may yet become available.
     #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     Timeout,
-    /// This channel's sending half has become disconnected, and there will
-    /// never be any more data received on this channel
+    /// The **channel**'s sending half has become disconnected, and there will
+    /// never be any more data received on it.
     #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     Disconnected,
 }
 
 /// This enumeration is the list of the possible error outcomes for the
-/// [`SyncSender::try_send`] method.
+/// [`try_send`] method.
 ///
-/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send
+/// [`try_send`]: struct.SyncSender.html#method.try_send
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub enum TrySendError<T> {
-    /// The data could not be sent on the channel because it would require that
+    /// The data could not be sent on the [`sync_channel`] because it would require that
     /// the callee block to send the data.
     ///
     /// If this is a buffered channel, then the buffer is full at this time. If
-    /// this is not a buffered channel, then there is no receiver available to
+    /// this is not a buffered channel, then there is no [`Receiver`] available to
     /// acquire the data.
+    ///
+    /// [`sync_channel`]: fn.sync_channel.html
+    /// [`Receiver`]: struct.Receiver.html
     #[stable(feature = "rust1", since = "1.0.0")]
     Full(#[stable(feature = "rust1", since = "1.0.0")] T),
 
-    /// This channel's receiving half has disconnected, so the data could not be
+    /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be
     /// sent. The data is returned back to the callee in this case.
+    ///
+    /// [`sync_channel`]: fn.sync_channel.html
     #[stable(feature = "rust1", since = "1.0.0")]
     Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T),
 }
@@ -544,15 +560,27 @@ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
 }
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
-/// All data sent on the sender will become available on the receiver, and no
-/// send will block the calling thread (this channel has an "infinite buffer").
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
+/// only one [`Receiver`] is supported.
 ///
 /// If the [`Receiver`] is disconnected while trying to [`send`] with the
-/// [`Sender`], the [`send`] method will return an error.
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
 ///
-/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
-/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`send`]: struct.Sender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Sender`]: struct.Sender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
 ///
 /// # Examples
 ///
@@ -560,20 +588,18 @@ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
 /// use std::sync::mpsc::channel;
 /// use std::thread;
 ///
-/// // tx is the sending half (tx for transmission), and rx is the receiving
-/// // half (rx for receiving).
-/// let (tx, rx) = channel();
+/// let (sender, receiver) = channel();
 ///
 /// // Spawn off an expensive computation
 /// thread::spawn(move|| {
 /// #   fn expensive_computation() {}
-///     tx.send(expensive_computation()).unwrap();
+///     sender.send(expensive_computation()).unwrap();
 /// });
 ///
 /// // Do some useful work for awhile
 ///
 /// // Let's see what that answer was
-/// println!("{:?}", rx.recv().unwrap());
+/// println!("{:?}", receiver.recv().unwrap());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
@@ -582,24 +608,32 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 }
 
 /// Creates a new synchronous, bounded channel.
-///
-/// Like asynchronous channels, the [`Receiver`] will block until a message
-/// becomes available. These channels differ greatly in the semantics of the
-/// sender from asynchronous channels, however.
+/// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
 ///
 /// This channel has an internal buffer on which messages will be queued.
 /// `bound` specifies the buffer size. When the internal buffer becomes full,
 /// future sends will *block* waiting for the buffer to open up. Note that a
 /// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
-/// where each [`send`] will not return until a recv is paired with it.
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple
+/// times, but only one [`Receiver`] is supported.
 ///
-/// Like asynchronous channels, if the [`Receiver`] is disconnected while
-/// trying to [`send`] with the [`SyncSender`], the [`send`] method will
-/// return an error.
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`SyncSender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
 ///
-/// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
-/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`SyncSender`]: struct.SyncSender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
 ///
 /// # Examples
 ///
@@ -607,18 +641,18 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 /// use std::sync::mpsc::sync_channel;
 /// use std::thread;
 ///
-/// let (tx, rx) = sync_channel(1);
+/// let (sender, receiver) = sync_channel(1);
 ///
 /// // this returns immediately
-/// tx.send(1).unwrap();
+/// sender.send(1).unwrap();
 ///
 /// thread::spawn(move|| {
 ///     // this will block until the previous message has been received
-///     tx.send(2).unwrap();
+///     sender.send(2).unwrap();
 /// });
 ///
-/// assert_eq!(rx.recv().unwrap(), 1);
-/// assert_eq!(rx.recv().unwrap(), 2);
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
index f2c178a1ad503f6e21f62ac574b41bb759a40316..a27f621e6b2ae7390a2c0811518729133d3f18bb 100644 (file)
@@ -61,7 +61,7 @@
 /// let data = Arc::new(Mutex::new(0));
 ///
 /// let (tx, rx) = channel();
-/// for _ in 0..10 {
+/// for _ in 0..N {
 ///     let (data, tx) = (data.clone(), tx.clone());
 ///     thread::spawn(move || {
 ///         // The shared state can only be accessed once the lock is held.
index d9d13240fcc3acc9a7ec9e4c27138182152cc215..0127a9eb7596944cafc2bd0457eca9b8e24f6084 100644 (file)
@@ -73,7 +73,9 @@ pub struct PoisonError<T> {
 }
 
 /// An enumeration of possible errors which can occur while calling the
-/// `try_lock` method.
+/// [`try_lock`] method.
+///
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum TryLockError<T> {
     /// The lock could not be acquired because another thread failed while holding
index c68e2ae34687b347cc095ca3b6d7787ec3c265db..08762ccf04bde8d0dbaaf6a638402384cbe10262 100644 (file)
@@ -343,6 +343,9 @@ pub fn new() -> Features {
 
     // Used to preserve symbols (see llvm.used)
     (active, used, "1.18.0", Some(40289)),
+
+    // Hack to document `-Z linker-flavor` in The Unstable Book
+    (active, linker_flavor, "1.18.0", Some(41142)),
 );
 
 declare_features! (
index 43d21015a4fb14569ac0f1635ae18b218b1bc550..58be43526fd9d7e6da9ddc0572ec177c63ea482c 100644 (file)
@@ -592,8 +592,10 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
             } else {
                 label_sp
             };
-            err.span_label(sp, &label_exp);
-            if !sp.source_equal(&self.span) {
+            if self.span.contains(sp) {
+                err.span_label(self.span, &label_exp);
+            } else {
+                err.span_label(sp, &label_exp);
                 err.span_label(self.span, &"unexpected token");
             }
             Err(err)
index c537a0ee16644d7e241a9a157488a46c9f47e613..a74f59b004bb76116ef75f4789f9bb4df58dcfca 100644 (file)
@@ -932,3 +932,137 @@ fn foo() {
 
 "#);
 }
+
+#[test]
+fn long_snippet() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "X1",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Z1",
+                count: 1,
+            },
+            end: Position {
+                string: "Z3",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+    ],
+    r#"
+error: foo
+  --> test.rs:3:6
+   |
+3  |      X0 Y0 Z0
+   |   ______^ starting here...
+4  |  |   X1 Y1 Z1
+   |  |____^____- starting here...
+   | ||____|
+   | |     ...ending here: `X` is a good letter
+5  | |  1
+6  | |  2
+7  | |  3
+...  |
+15 | |    X2 Y2 Z2
+16 | |    X3 Y3 Z3
+   | |___________- ...ending here: `Y` is a good letter too
+
+"#);
+}
+
+#[test]
+fn long_snippet_multiple_spans() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0 Z0
+1
+2
+3
+  X1 Y1 Z1
+4
+5
+6
+  X2 Y2 Z2
+7
+8
+9
+10
+  X3 Y3 Z3
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "Y3",
+                count: 1,
+            },
+            label: "`Y` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Z1",
+                count: 1,
+            },
+            end: Position {
+                string: "Z2",
+                count: 1,
+            },
+            label: "`Z` is a good letter too",
+        },
+    ],
+    r#"
+error: foo
+  --> test.rs:3:6
+   |
+3  |      X0 Y0 Z0
+   |   ______^ starting here...
+4  |  | 1
+5  |  | 2
+6  |  | 3
+7  |  |   X1 Y1 Z1
+   |  |_________- starting here...
+8  | || 4
+9  | || 5
+10 | || 6
+11 | ||   X2 Y2 Z2
+   | ||__________- ...ending here: `Z` is a good letter too
+...   |
+15 |  | 10
+16 |  |   X3 Y3 Z3
+   |  |_______^ ...ending here: `Y` is a good letter
+
+"#);
+}
+
index 9b88b9f7696fb3a35f68c5165d3f5ccc59ce610f..aaafcadc38a1468e8177fdc123a7c726f3483515 100644 (file)
@@ -89,7 +89,7 @@ pub fn end_point(self) -> Span {
     /// Returns a new span representing the next character after the end-point of this span
     pub fn next_point(self) -> Span {
         let lo = cmp::max(self.hi.0, self.lo.0 + 1);
-        Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self }
+        Span { lo: BytePos(lo), hi: BytePos(lo), ..self }
     }
 
     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
index 76313b158ab1109422938a7368706a81838b5d9f..bc84ac49da985a11166ccc4e2c80793f45291e63 100644 (file)
@@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {
 fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly)
 #[no_mangle]
 fn trait_box(_: Box<Drop>) {
 }
diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs
new file mode 100644 (file)
index 0000000..955ec39
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is a fake compile fail test as there's no way to generate a
+// `#![feature(linker_flavor)]` error. The only reason we have a `linker_flavor`
+// feature gate is to be able to document `-Z linker-flavor` in the unstable
+// book
+
+#[used]
+fn foo() {}
+//~^^ ERROR the `#[used]` attribute is an experimental feature
+
+fn main() {}
index 521f122f8af0b57eec342d14cadd72fee2904610..48c9fda31e8c80707674537252d6a2fe4306d0a9 100644 (file)
 
 #![feature(core_intrinsics)]
 
-use std::intrinsics::{init, forget};
+use std::intrinsics::{init};
 
 // Test that the `forget` and `init` intrinsics are really unsafe
 pub fn main() {
     let stuff = init::<isize>(); //~ ERROR call to unsafe function requires unsafe
-    forget(stuff);             //~ ERROR call to unsafe function requires unsafe
 }
diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/compile-fail/impl-trait/equality.rs
deleted file mode 100644 (file)
index 36df4f0..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(conservative_impl_trait, specialization)]
-
-trait Foo: Copy + ToString {}
-
-impl<T: Copy + ToString> Foo for T {}
-
-fn hide<T: Foo>(x: T) -> impl Foo {
-    x
-}
-
-fn two(x: bool) -> impl Foo {
-    if x {
-        return 1_i32;
-    }
-    0_u32
-    //~^ ERROR mismatched types
-    //~| expected i32, found u32
-}
-
-fn sum_to(n: u32) -> impl Foo {
-    if n == 0 {
-        0
-    } else {
-        n + sum_to(n - 1)
-        //~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
-    }
-}
-
-trait Leak: Sized {
-    type T;
-    fn leak(self) -> Self::T;
-}
-impl<T> Leak for T {
-    default type T = ();
-    default fn leak(self) -> Self::T { panic!() }
-}
-impl Leak for i32 {
-    type T = i32;
-    fn leak(self) -> i32 { self }
-}
-
-fn main() {
-    let _: u32 = hide(0_u32);
-    //~^ ERROR mismatched types
-    //~| expected type `u32`
-    //~| found type `impl Foo`
-    //~| expected u32, found anonymized type
-
-    let _: i32 = Leak::leak(hide(0_i32));
-    //~^ ERROR mismatched types
-    //~| expected type `i32`
-    //~| found type `<impl Foo as Leak>::T`
-    //~| expected i32, found associated type
-
-    let mut x = (hide(0_u32), hide(0_i32));
-    x = (x.1,
-    //~^ ERROR mismatched types
-    //~| expected u32, found i32
-         x.0);
-    //~^ ERROR mismatched types
-    //~| expected i32, found u32
-}
index b7083c2776aeccd3f5575be4e55c25dc7222d0f9..14515ad7f00b91f9c4c140b6e5e15351d25968d2 100644 (file)
@@ -1,5 +1,6 @@
 {
     "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
+    "linker-flavor": "gcc",
     "llvm-target": "i686-unknown-linux-gnu",
     "target-endian": "little",
     "target-pointer-width": "32",
index 053f2dd63358a9b9e832e5dbaaf7831e5752b445..74787b28d2233905382e8960af5b8ee003299867 100644 (file)
@@ -1,5 +1,6 @@
 {
     "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32",
+    "linker-flavor": "gcc",
     "target-endian": "little",
     "target-pointer-width": "32",
     "arch": "x86",
index 688bbe46bfaf0593b6df26e2a1035ee0952ee272..cfe152f9e8728c0a3fb294de11c324d4210b9895 100644 (file)
@@ -1,6 +1,7 @@
 {
     "pre-link-args": ["-m64"],
     "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128",
+    "linker-flavor": "gcc",
     "llvm-target": "x86_64-unknown-linux-gnu",
     "target-endian": "little",
     "target-pointer-width": "64",
diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs
new file mode 100644 (file)
index 0000000..3832c04
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=0
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+    assert_eq!(size_of::<S1>(), 6);
+    assert_eq!(size_of::<S2>(), 6);
+}
+
diff --git a/src/test/run-pass/optimization-fuel-1.rs b/src/test/run-pass/optimization-fuel-1.rs
new file mode 100644 (file)
index 0000000..5f294e2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=1
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+    let optimized = (size_of::<S1>() == 4) as usize
+        +(size_of::<S2>() == 4) as usize;
+    assert_eq!(optimized, 1);
+}
+
+
index bbb01eaaf46b9b43afbdbf4bdbf4c7ebfbf4aa61..2f50e63153ea4bf8722b3bec2458aaa40d6168be 100644 (file)
@@ -31,6 +31,17 @@ enum e3 {
     a([u16; 0], u8), b
 }
 
+struct ReorderedStruct {
+    a: u8,
+    b: u16,
+    c: u8
+}
+
+enum ReorderedEnum {
+    A(u8, u16, u8),
+    B(u8, u16, u8),
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -54,4 +65,6 @@ pub fn main() {
     assert_eq!(size_of::<e1>(), 8 as usize);
     assert_eq!(size_of::<e2>(), 8 as usize);
     assert_eq!(size_of::<e3>(), 4 as usize);
+    assert_eq!(size_of::<ReorderedStruct>(), 4);
+    assert_eq!(size_of::<ReorderedEnum>(), 6);
 }
index 89c5e60e3431430611ffd6c0e49bff211575b6b8..48ef4b6be66dea34e4d204f8ce7eba6bce392b74 100644 (file)
@@ -17,7 +17,7 @@ impl AnOibit for .. {}
 pub struct Foo<T> { field: T }
 
 // @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
-//     "impl<T: Clone> !AnOibit for Foo<T> where T: Sync"
+//     "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
 // @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \
-//     "impl<T: Clone> !AnOibit for Foo<T> where T: Sync"
+//     "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
 impl<T: Clone> !AnOibit for Foo<T> where T: Sync {}
index 9ebd1c448eeb0d4195479782b9e066531b043188..960e40b07098567491d48b8936a0fe4a7b757b09 100644 (file)
@@ -35,7 +35,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 
 pub mod reexport {
     // @has issue_20727_4/reexport/trait.Index.html
-    // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized {'
+    // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {'
     // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
     // @has - '//*[@class="rust trait"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
@@ -43,7 +43,7 @@ pub mod reexport {
 
     // @has issue_20727_4/reexport/trait.IndexMut.html
     // @has - '//*[@class="rust trait"]' \
-    //        'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized {'
+    //        'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {'
     // @has - '//*[@class="rust trait"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     pub use issue_20727::IndexMut;
index d8dc115abf91e1039fa8b30561540c43ed79a753..e691f7c5bea01ef8e054f78e1cc71c7c9bcb7492 100644 (file)
@@ -44,5 +44,5 @@ pub enum Foxtrot<F> { Foxtrot1(F) }
 impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
 
 // @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
-//          "type Golf<T> where T: Clone = (T, T)"
+//          "type Golf<T> where T: Clone, = (T, T)"
 pub type Golf<T> where T: Clone = (T, T);
diff --git a/src/test/ui/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs
new file mode 100644 (file)
index 0000000..96db53a
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, specialization)]
+
+trait Foo: Copy + ToString {}
+
+impl<T: Copy + ToString> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+    x
+}
+
+fn two(x: bool) -> impl Foo {
+    if x {
+        return 1_i32;
+    }
+    0_u32
+    //~^ ERROR mismatched types
+    //~| expected i32, found u32
+}
+
+fn sum_to(n: u32) -> impl Foo {
+    if n == 0 {
+        0
+    } else {
+        n + sum_to(n - 1)
+        //~^ ERROR no implementation for `u32 + impl Foo`
+    }
+}
+
+trait Leak: Sized {
+    type T;
+    fn leak(self) -> Self::T;
+}
+impl<T> Leak for T {
+    default type T = ();
+    default fn leak(self) -> Self::T { panic!() }
+}
+impl Leak for i32 {
+    type T = i32;
+    fn leak(self) -> i32 { self }
+}
+
+fn main() {
+    let _: u32 = hide(0_u32);
+    //~^ ERROR mismatched types
+    //~| expected type `u32`
+    //~| found type `impl Foo`
+    //~| expected u32, found anonymized type
+
+    let _: i32 = Leak::leak(hide(0_i32));
+    //~^ ERROR mismatched types
+    //~| expected type `i32`
+    //~| found type `<impl Foo as Leak>::T`
+    //~| expected i32, found associated type
+
+    let mut x = (hide(0_u32), hide(0_i32));
+    x = (x.1,
+    //~^ ERROR mismatched types
+    //~| expected u32, found i32
+         x.0);
+    //~^ ERROR mismatched types
+    //~| expected i32, found u32
+}
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
new file mode 100644 (file)
index 0000000..bd024d6
--- /dev/null
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/equality.rs:25:5
+   |
+25 |     0_u32
+   |     ^^^^^ expected i32, found u32
+   |
+   = note: expected type `i32`
+              found type `u32`
+
+error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+  --> $DIR/equality.rs:34:9
+   |
+34 |         n + sum_to(n - 1)
+   |         ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
+   |
+   = note: no implementation for `u32 + impl Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/equality.rs:53:18
+   |
+53 |     let _: u32 = hide(0_u32);
+   |                  ^^^^^^^^^^^ expected u32, found anonymized type
+   |
+   = note: expected type `u32`
+              found type `impl Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/equality.rs:59:18
+   |
+59 |     let _: i32 = Leak::leak(hide(0_i32));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type
+   |
+   = note: expected type `i32`
+              found type `<impl Foo as Leak>::T`
+
+error[E0308]: mismatched types
+  --> $DIR/equality.rs:66:10
+   |
+66 |     x = (x.1,
+   |          ^^^ expected u32, found i32
+   |
+   = note: expected type `impl Foo` (u32)
+              found type `impl Foo` (i32)
+
+error[E0308]: mismatched types
+  --> $DIR/equality.rs:69:10
+   |
+69 |          x.0);
+   |          ^^^ expected i32, found u32
+   |
+   = note: expected type `impl Foo` (i32)
+              found type `impl Foo` (u32)
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs
new file mode 100644 (file)
index 0000000..98449e5
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    1 + Some(1);
+    2 as usize - Some(1);
+    3 * ();
+    4 / "";
+    5 < String::new();
+    6 == Ok(1);
+}
diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr
new file mode 100644 (file)
index 0000000..a0f7ff6
--- /dev/null
@@ -0,0 +1,58 @@
+error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
+  --> $DIR/binops.rs:12:5
+   |
+12 |     1 + Some(1);
+   |     ^^^^^^^^^^^ the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
+   |
+   = note: no implementation for `{integer} + std::option::Option<{integer}>`
+
+error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
+  --> $DIR/binops.rs:13:5
+   |
+13 |     2 as usize - Some(1);
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
+   |
+   = note: no implementation for `usize - std::option::Option<{integer}>`
+
+error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
+  --> $DIR/binops.rs:14:5
+   |
+14 |     3 * ();
+   |     ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}`
+   |
+   = note: no implementation for `{integer} * ()`
+
+error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
+  --> $DIR/binops.rs:15:5
+   |
+15 |     4 / "";
+   |     ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}`
+   |
+   = note: no implementation for `{integer} / &str`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
+  --> $DIR/binops.rs:16:5
+   |
+16 |     5 < String::new();
+   |     ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
+   |
+   = note: can't compare `{integer}` with `std::string::String`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
+  --> $DIR/binops.rs:16:5
+   |
+16 |     5 < String::new();
+   |     ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
+   |
+   = note: can't compare `{integer}` with `std::string::String`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
+  --> $DIR/binops.rs:17:5
+   |
+17 |     6 == Ok(1);
+   |     ^^^^^^^^^^ the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
+   |
+   = note: can't compare `{integer}` with `std::result::Result<{integer}, _>`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs
new file mode 100644 (file)
index 0000000..0d9e243
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+#![allow(dead_code)]
+
+// compile-flags: -Z print-fuel=foo
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+struct S3(u8, u16, u8);
+
+fn main() {
+}
diff --git a/src/test/ui/print-fuel/print-fuel.stdout b/src/test/ui/print-fuel/print-fuel.stdout
new file mode 100644 (file)
index 0000000..cc88cc0
--- /dev/null
@@ -0,0 +1 @@
+Fuel used by foo: 3
index dd999c4a5e4c779d1e30f105926d4a4ef4e07eda..830678f174f88cf38e0d76836bac2cc7c9a9ee96 100644 (file)
@@ -1,25 +1,22 @@
-print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
-print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.nested`: 12 bytes, alignment: 4 bytes
+print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.nested`: 8 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
-print-type-size     variant `Some`: 20 bytes
-print-type-size         field `.0`: 20 bytes
-print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
-print-type-size     variant `Record`: 10 bytes
-print-type-size         field `.pre`: 1 bytes
-print-type-size         padding: 3 bytes
-print-type-size         field `.val`: 4 bytes, alignment: 4 bytes
-print-type-size         field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
 print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
+print-type-size     variant `Some`: 12 bytes
+print-type-size         field `.0`: 12 bytes
+print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     variant `Record`: 7 bytes
+print-type-size         field `.val`: 4 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.val`: 4 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
+print-type-size     field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Some`: 4 bytes
 print-type-size         field `.0`: 4 bytes
index 1278a7d7c92c67836d9e74db7eefd791ef4b3b23..83fd333c9c7fc45dba547de22add55c477521ef9 100644 (file)
@@ -1,13 +1,11 @@
-print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
+print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
+print-type-size     field `.h`: 2 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.c`: 1 bytes
-print-type-size     padding: 1 bytes
-print-type-size     field `.h`: 2 bytes, alignment: 2 bytes
 print-type-size     field `.d`: 1 bytes
-print-type-size     end padding: 3 bytes
+print-type-size     end padding: 2 bytes
 print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
index bb95f790bd9e471bdd740e5f9817faf8af8d4f54..0eaff7118b35c38a528dab7052d2cd498acb15aa 100644 (file)
@@ -1,10 +1,12 @@
 print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
-print-type-size     discriminant: 4 bytes
-print-type-size     variant `A`: 5 bytes
-print-type-size         field `.0`: 4 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `A`: 7 bytes
 print-type-size         field `.1`: 1 bytes
-print-type-size     variant `B`: 8 bytes
-print-type-size         field `.0`: 8 bytes
+print-type-size         padding: 2 bytes
+print-type-size         field `.0`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `B`: 11 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `A`: 7 bytes
@@ -15,7 +17,7 @@ print-type-size     variant `B`: 11 bytes
 print-type-size         padding: 3 bytes
 print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `S`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 2 bytes
index 717f5ee200c74041e5aea5c3509ea17ef7e5869d..367af12bb6b1c2f122e667b001a41cacac78d00f 100644 (file)
@@ -24,8 +24,7 @@ error[E0046]: not all trait items implemented, missing: `bar`
 23 | |     //~^ ERROR E0046
 24 | |     //~| NOTE missing `bar` in implementation
 25 | |     const bar: u64 = 1;
-26 | |     //~^ ERROR E0323
-27 | |     //~| NOTE does not match trait
+...  |
 28 | |     const MY_CONST: u32 = 1;
 29 | | }
    | |_^ ...ending here: missing `bar` in implementation
@@ -50,8 +49,7 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST`
 34 | |     //~^ ERROR E0046
 35 | |     //~| NOTE missing `MY_CONST` in implementation
 36 | |     fn bar(&self) {}
-37 | |     fn MY_CONST() {}
-38 | |     //~^ ERROR E0324
+...  |
 39 | |     //~| NOTE does not match trait
 40 | | }
    | |_^ ...ending here: missing `MY_CONST` in implementation
@@ -76,8 +74,7 @@ error[E0046]: not all trait items implemented, missing: `bar`
 45 | |     //~^ ERROR E0046
 46 | |     //~| NOTE missing `bar` in implementation
 47 | |     type bar = u64;
-48 | |     //~^ ERROR E0325
-49 | |     //~| NOTE does not match trait
+...  |
 50 | |     const MY_CONST: u32 = 1;
 51 | | }
    | |_^ ...ending here: missing `bar` in implementation
index 493ca01778bc15de42d55ce7865f1e381bc2f9cf..701576ff6f475bf59e4eeb74eed2a637b7043968 100644 (file)
@@ -1,8 +1,15 @@
 error[E0046]: not all trait items implemented, missing: `Item`
   --> $DIR/issue-23729.rs:20:9
    |
-20 |         impl Iterator for Recurrence {
-   |         ^ missing `Item` in implementation
+20 |           impl Iterator for Recurrence {
+   |  _________^ starting here...
+21 | |             //~^ ERROR E0046
+22 | |             //~| NOTE missing `Item` in implementation
+23 | |             //~| NOTE `Item` from trait: `type Item;`
+...  |
+36 | |             }
+37 | |         }
+   | |_________^ ...ending here: missing `Item` in implementation
    |
    = note: `Item` from trait: `type Item;`
 
index 6c1c246753011d907a3df7d00185e8f2498c4237..457fed34ff1ad9807d41d62889090436273f9472 100644 (file)
@@ -6,8 +6,7 @@ error[E0046]: not all trait items implemented, missing: `Output`
 37 | |     //~^ ERROR E0046
 38 | |     //~| NOTE missing `Output` in implementation
 39 | |     //~| NOTE `Output` from trait: `type Output;`
-40 | |     extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype {
-41 | |         Fn::call(&self, (comp,))
+...  |
 42 | |     }
 43 | | }
    | |_^ ...ending here: missing `Output` in implementation
index 85c11c05b9f9004c55a54d303433e11de586340b..161b6ca48b282444edf6150f4d847eb7df3903a6 100644 (file)
@@ -9,11 +9,7 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
 27 | |             y),
    | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32`
    |
-   = help: the following implementations were found:
-             <u32 as std::ops::Add>
-             <&'a u32 as std::ops::Add<u32>>
-             <u32 as std::ops::Add<&'a u32>>
-             <&'b u32 as std::ops::Add<&'a u32>>
+   = note: no implementation for `u32 + ()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/token/issue-41155.rs b/src/test/ui/token/issue-41155.rs
new file mode 100644 (file)
index 0000000..0f473c9
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+impl S {
+    pub
+}
diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr
new file mode 100644 (file)
index 0000000..0da3abd
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
+  --> $DIR/issue-41155.rs:13:1
+   |
+12 |     pub
+   |        - expected one of 7 possible tokens here
+13 | }
+   | ^ unexpected token
+
+error: aborting due to previous error
+
index ef93b0858b02f646068332f6c47fb521bb9e9a20..11d5dbe736e81cdd39230a536bfd35210ad10131 100644 (file)
@@ -62,8 +62,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                 });
             let path_bytes = rel_path.as_os_str().as_bytes();
             if output.status.success() && output.stdout.starts_with(path_bytes) {
-                println!("binary checked into source: {}", file.display());
-                *bad = true;
+                tidy_error!(bad, "binary checked into source: {}", file.display());
             }
         }
     })
index 053f0bbe3b81d321a86f23b320c9937a54a4b2ec..c8c6cb0ee6b418f53453b17fd316ca4679d4393f 100644 (file)
@@ -100,9 +100,8 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
         }
 
         if !librs.contains(&format!("extern crate {}", krate)) {
-            println!("{} doesn't have `extern crate {}`, but Cargo.toml \
-                      depends on it", libfile.display(), krate);
-            *bad = true;
+            tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \
+                              depends on it", libfile.display(), krate);
         }
     }
 }
index 3a70e54ff9745d457b24f0f320eee2fbec43e74d..5bf7c894cda66ecbc2e361d5549c31f787966c3e 100644 (file)
@@ -79,11 +79,10 @@ pub fn check(path: &Path, bad: &mut bool) {
             continue
         }
 
-        println!("duplicate error code: {}", code);
+        tidy_error!(bad, "duplicate error code: {}", code);
         for &(ref file, line_num, ref line) in entries.iter() {
-            println!("{}:{}: {}", file.display(), line_num, line);
+            tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line);
         }
-        *bad = true;
     }
 
     if !*bad {
index e1fdc19c27d2585a902cd19bfcd203707fd809de..ad0d2fa0b363567da15144ddaa4de22aee9b62d9 100644 (file)
@@ -77,8 +77,7 @@ pub fn check(path: &Path, bad: &mut bool) {
 
         for (i, line) in contents.lines().enumerate() {
             let mut err = |msg: &str| {
-                println!("{}:{}: {}", file.display(), i + 1, msg);
-                *bad = true;
+                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
 
             let gate_test_str = "gate-test-";
@@ -126,8 +125,7 @@ pub fn check(path: &Path, bad: &mut bool) {
     }
 
     if gate_untested.len() > 0 {
-        println!("Found {} features without a gate test.", gate_untested.len());
-        *bad = true;
+        tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
     }
 
     if *bad {
@@ -221,8 +219,7 @@ pub fn collect_lib_features(base_src_path: &Path,
 
         for (i, line) in contents.lines().enumerate() {
             let mut err = |msg: &str| {
-                println!("{}:{}: {}", file.display(), i + 1, msg);
-                *bad = true;
+                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
             let level = if line.contains("[unstable(") {
                 Status::Unstable
index 501e35e03e8a70e971fb827c2155304e54045911..dee37341051ed2f0227a09f8878c248f0984a488 100644 (file)
 
 extern crate regex;
 
+use std::env;
 use std::fs;
+use std::io::{self, Write};
 use std::path::{PathBuf, Path};
-use std::env;
+use std::process;
 
 macro_rules! t {
     ($e:expr, $p:expr) => (match $e {
@@ -32,6 +34,15 @@ macro_rules! t {
     })
 }
 
+macro_rules! tidy_error {
+    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
+        use std::io::Write;
+        *$bad = true;
+        write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr");
+        writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr");
+    });
+}
+
 mod bins;
 mod style;
 mod errors;
@@ -60,7 +71,8 @@ fn main() {
     }
 
     if bad {
-        panic!("some tidy checks failed");
+        writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr");
+        process::exit(1);
     }
 }
 
index 0dbf0d4316abd9c2cdc92ee7794747168f7b69c7..1065749a6961ce5c19fcfcde01fbabccfc5517b7 100644 (file)
@@ -126,8 +126,7 @@ fn check_cfgs(contents: &mut String, file: &Path,
             Ok(_) => unreachable!(),
             Err(i) => i + 1
         };
-        println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
-        *bad = true;
+        tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
     };
 
     for (idx, cfg) in cfgs.into_iter() {
index 012301299e0c54029a72cf35de4663bab803ff87..d545a03aa5ccb8f7d440800187f30cfd57506f78 100644 (file)
@@ -113,8 +113,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace");
         for (i, line) in contents.split("\n").enumerate() {
             let mut err = |msg: &str| {
-                println!("{}:{}: {}", file.display(), i + 1, msg);
-                *bad = true;
+                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
             if !skip_length && line.chars().count() > COLS
                 && !long_line_is_ok(line) {
@@ -139,8 +138,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             }
         }
         if !licenseck(file, &contents) {
-            println!("{}: incorrect license", file.display());
-            *bad = true;
+            tidy_error!(bad, "{}: incorrect license", file.display());
         }
     })
 }
index c10e31077944f0950e496115e7a5864444573832..2d3d9e80257f9019d7d62db5d17e8b227e9e09b5 100644 (file)
@@ -10,7 +10,7 @@
 
 use std::collections::HashSet;
 use std::fs;
-use std::io::{self, BufRead, Write};
+use std::io::{self, BufRead};
 use std::path;
 use features::{collect_lang_features, collect_lib_features, Status};
 
@@ -110,29 +110,26 @@ pub fn check(path: &path::Path, bad: &mut bool) {
 
     // Check for Unstable Book section names with no corresponding SUMMARY.md link
     for feature_name in &unstable_book_section_file_names - &unstable_book_links {
-        *bad = true;
-        writeln!(io::stderr(),
-                 "The Unstable Book section '{}' needs to have a link in SUMMARY.md",
-                 feature_name)
-                .expect("could not write to stderr")
+        tidy_error!(
+            bad,
+            "The Unstable Book section '{}' needs to have a link in SUMMARY.md",
+            feature_name);
     }
 
     // Check for unstable features that don't have Unstable Book sections
     for feature_name in &unstable_feature_names - &unstable_book_section_file_names {
-        *bad = true;
-        writeln!(io::stderr(),
-                 "Unstable feature '{}' needs to have a section in The Unstable Book",
-                 feature_name)
-                .expect("could not write to stderr")
+        tidy_error!(
+            bad,
+            "Unstable feature '{}' needs to have a section in The Unstable Book",
+            feature_name);
     }
 
     // Check for Unstable Book sections that don't have a corresponding unstable feature
     for feature_name in &unstable_book_section_file_names - &unstable_feature_names {
-        *bad = true;
-        writeln!(io::stderr(),
-                 "The Unstable Book has a section '{}' which doesn't correspond \
-                  to an unstable feature",
-                 feature_name)
-                .expect("could not write to stderr")
+        tidy_error!(
+            bad,
+            "The Unstable Book has a section '{}' which doesn't correspond \
+            to an unstable feature",
+            feature_name)
     }
 }