]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #41258 - clarcharr:str_box_extras, r=Kimundi
authorbors <bors@rust-lang.org>
Wed, 26 Apr 2017 06:18:17 +0000 (06:18 +0000)
committerbors <bors@rust-lang.org>
Wed, 26 Apr 2017 06:18:17 +0000 (06:18 +0000)
More methods for str boxes. (reduce Box<[u8]> ↔ Box<str> transmutes)

This is a follow-up to #41096 that adds safer methods for converting between `Box<str>` and `Box<[u8]>`. They're gated under a different feature from the `&mut str` methods because they may be too niche to include in public APIs, although having them internally helps reduce the number of transmutes the standard library uses.

What's added:

* `From<Box<str>> for Box<[u8]>`
* `<Box<str>>::into_boxed_bytes` (just calls `Into::into`)
* `alloc::str` (new module)
* `from_boxed_utf8` and `from_boxed_utf8_unchecked`, defined in `alloc:str`, exported in `collections::str`
* exports `from_utf8_mut` in `collections::str` (missed from previous PR)

260 files changed:
appveyor.yml
cargo
configure
rls
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/step.rs
src/ci/docker/dist-android/Dockerfile
src/ci/docker/dist-android/install-ndk.sh
src/ci/docker/emscripten/Dockerfile
src/ci/docker/emscripten/build-emscripten.sh
src/compiler-rt
src/doc/grammar.md
src/doc/index.md
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/language-features/repr-align.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/as-unsafe-cell.md [deleted file]
src/doc/unstable-book/src/library-features/binary-heap-extras.md [deleted file]
src/doc/unstable-book/src/library-features/borrow-state.md [deleted file]
src/doc/unstable-book/src/library-features/enumset.md [deleted file]
src/doc/unstable-book/src/library-features/float-extras.md [deleted file]
src/doc/unstable-book/src/library-features/is-unique.md [deleted file]
src/doc/unstable-book/src/library-features/map-entry-recover-keys.md [deleted file]
src/doc/unstable-book/src/library-features/more-io-inner-methods.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/rc-would-unwrap.md [deleted file]
src/doc/unstable-book/src/library-features/splice.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/zero-one.md [deleted file]
src/etc/rust-gdb
src/etc/rust-windbg.cmd [new file with mode: 0644]
src/liballoc/heap.rs
src/liballoc/lib.rs
src/liballoc/rc.rs
src/libcollections/binary_heap.rs
src/libcollections/btree/map.rs
src/libcollections/btree/set.rs
src/libcollections/enum_set.rs [deleted file]
src/libcollections/lib.rs
src/libcollections/linked_list.rs
src/libcollections/slice.rs
src/libcollections/string.rs
src/libcollections/tests/binary_heap.rs
src/libcollections/tests/lib.rs
src/libcollections/tests/string.rs
src/libcollections/tests/vec.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcompiler_builtins/build.rs
src/libcore/cell.rs
src/libcore/convert.rs
src/libcore/fmt/num.rs
src/libcore/iter/iterator.rs
src/libcore/marker.rs
src/libcore/num/dec2flt/rawfp.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/num/flt2dec/decoder.rs
src/libcore/num/mod.rs
src/libcore/tests/num/dec2flt/rawfp.rs
src/liblibc
src/librustc/dep_graph/dep_node.rs
src/librustc/diagnostics.rs
src/librustc/hir/check_attr.rs
src/librustc/ich/impls_ty.rs
src/librustc/infer/freshen.rs
src/librustc/infer/region_inference/mod.rs
src/librustc/middle/const_val.rs
src/librustc/middle/cstore.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/reachable.rs
src/librustc/mir/mod.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/mod.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/select.rs
src/librustc/traits/trans/mod.rs [new file with mode: 0644]
src/librustc/ty/contents.rs [deleted file]
src/librustc/ty/context.rs
src/librustc/ty/fold.rs
src/librustc/ty/instance.rs
src/librustc/ty/layout.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc/ty/subst.rs
src/librustc/ty/util.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/x86_64_linux_android.rs [new file with mode: 0644]
src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
src/librustc_borrowck/borrowck/mir/mod.rs
src/librustc_const_eval/eval.rs
src/librustc_const_eval/pattern.rs
src/librustc_driver/driver.rs
src/librustc_driver/test.rs
src/librustc_errors/emitter.rs
src/librustc_errors/snippet.rs
src/librustc_lint/builtin.rs
src/librustc_llvm/build.rs
src/librustc_llvm/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/erase_regions.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/simplify.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_passes/consts.rs
src/librustc_privacy/lib.rs
src/librustc_trans/abi.rs
src/librustc_trans/adt.rs
src/librustc_trans/back/symbol_export.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/base.rs
src/librustc_trans/builder.rs
src/librustc_trans/callee.rs
src/librustc_trans/collector.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/lib.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/monomorphize.rs
src/librustc_trans/partitioning.rs
src/librustc_trans/symbol_cache.rs [new file with mode: 0644]
src/librustc_trans/symbol_map.rs
src/librustc_trans/symbol_names_test.rs
src/librustc_trans/trans_item.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/clean/inline.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/test.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/set.rs
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/io/mod.rs
src/libstd/lib.rs
src/libstd/num.rs
src/libstd/os/android/raw.rs
src/libstd/path.rs
src/libstd/process.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sys/unix/time.rs
src/libsyntax/attr.rs
src/libsyntax/diagnostic_list.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/parser.rs
src/libsyntax/test_snippet.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/llvm
src/rtstartup/rsbegin.rs
src/test/codegen/drop.rs
src/test/codegen/personality_lifetimes.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs [new file with mode: 0644]
src/test/compile-fail/attr-usage-repr.rs
src/test/compile-fail/coercion-slice.rs
src/test/compile-fail/conflicting-repr-hints.rs
src/test/compile-fail/const-call.rs
src/test/compile-fail/const-pattern-not-const-evaluable.rs
src/test/compile-fail/cross-borrow-trait.rs
src/test/compile-fail/feature-gate-repr_align.rs [new file with mode: 0644]
src/test/compile-fail/issue-11374.rs
src/test/compile-fail/issue-13058.rs
src/test/compile-fail/issue-28514.rs [deleted file]
src/test/compile-fail/issue-39559.rs
src/test/compile-fail/issue-41394.rs [new file with mode: 0644]
src/test/compile-fail/no-method-suggested-traits.rs
src/test/compile-fail/non-constant-enum-for-vec-repeat.rs [deleted file]
src/test/compile-fail/object-safety-associated-consts.rs [new file with mode: 0644]
src/test/compile-fail/privacy/union-field-privacy-1.rs
src/test/compile-fail/repr-align.rs [new file with mode: 0644]
src/test/compile-fail/repr-packed-contains-align.rs [new file with mode: 0644]
src/test/compile-fail/trait-item-privacy.rs [new file with mode: 0644]
src/test/compile-fail/trait-not-accessible.rs [deleted file]
src/test/parse-fail/bound-single-question-mark.rs [new file with mode: 0644]
src/test/parse-fail/trait-object-bad-parens.rs [new file with mode: 0644]
src/test/parse-fail/trait-object-lifetime-parens.rs [new file with mode: 0644]
src/test/parse-fail/trait-object-trait-parens.rs [new file with mode: 0644]
src/test/run-make/simd-ffi/simd.rs
src/test/run-make/target-specs/foo.rs
src/test/run-pass/align-struct.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/issue-41394.rs [new file with mode: 0644]
src/test/run-pass/const-pattern-variant.rs [new file with mode: 0644]
src/test/run-pass/issue-23898.rs [new file with mode: 0644]
src/test/run-pass/issue-29663.rs
src/test/run-pass/issue-41394.rs [new file with mode: 0644]
src/test/run-pass/issue-8460.rs
src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
src/test/run-pass/panic-runtime/abort.rs
src/test/run-pass/sync-send-iterators-in-libcollections.rs
src/test/run-pass/union/union-transmute.rs
src/test/run-pass/while-let.rs
src/test/rustdoc/check-hard-break.rs [deleted file]
src/test/rustdoc/check-rule-image-footnote.rs [deleted file]
src/test/ui/compare-method/region-extra-2.stderr
src/test/ui/compare-method/traits-misc-mismatch-2.stderr
src/test/ui/did_you_mean/issue-40006.stderr
src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
src/test/ui/issue-37311-type-length-limit/issue-37311.stderr
src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr
src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr
src/test/ui/mismatched_types/abridged.stderr
src/test/ui/mismatched_types/main.stderr
src/test/ui/missing-items/m2.stderr
src/test/ui/print_type_sizes/repr-align.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/repr-align.stdout [new file with mode: 0644]
src/test/ui/span/coerce-suggestions.rs
src/test/ui/span/coerce-suggestions.stderr
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/issue-24356.stderr
src/test/ui/span/issue-33884.rs [new file with mode: 0644]
src/test/ui/span/issue-33884.stderr [new file with mode: 0644]
src/test/ui/span/issue-7575.stderr
src/test/ui/span/lint-unused-unsafe.stderr
src/test/ui/span/multiline-span-E0072.stderr
src/test/ui/span/multiline-span-simple.stderr
src/test/ui/type-check/issue-40294.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargotest/main.rs
src/tools/error_index_generator/main.rs

index 5de5f3bd26c38b9ec8297cf0aa5cabe8c9ecb2f0..f0589b0e645616d688884310a98c66fd5908510a 100644 (file)
@@ -20,39 +20,28 @@ environment:
 
   # 32/64-bit MinGW builds.
   #
-  # The MinGW builds unfortunately have to both download a custom toolchain and
-  # avoid the one installed by AppVeyor by default. Interestingly, though, for
-  # different reasons!
+  # We are using MinGW with posix threads since LLVM does not compile with
+  # the win32 threads version due to missing support for C++'s std::thread.
   #
-  # For 32-bit the installed gcc toolchain on AppVeyor uses the pthread
-  # threading model. This is unfortunately not what we want, and if we compile
-  # with it then there's lots of link errors in the standard library (undefined
-  # references to pthread symbols).
-  #
-  # For 64-bit the installed gcc toolchain is currently 5.3.0 which
-  # unfortunately segfaults on Windows with --enable-llvm-assertions (segfaults
-  # in LLVM). See rust-lang/rust#28445 for more information, but to work around
-  # this we go back in time to 4.9.2 specifically.
+  # Instead of relying on the MinGW version installed on appveryor we download
+  # and install one ourselves so we won't be surprised by changes to appveyor's
+  # build image.
   #
   # Finally, note that the downloads below are all in the `rust-lang-ci` S3
   # bucket, but they cleraly didn't originate there! The downloads originally
   # came from the mingw-w64 SourceForge download site. Unfortunately
   # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
-  #
-  # And as a final point of note, the 32-bit MinGW build using the makefiles do
-  # *not* use debug assertions and llvm assertions. This is because they take
-  # too long on appveyor and this is tested by rustbuild below.
   - MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja
     SCRIPT: python x.py test
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror
-    MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z
+    MINGW_ARCHIVE: i686-6.2.0-release-posix-dwarf-rt_v5-rev1.7z
     MINGW_DIR: mingw32
   - MSYS_BITS: 64
     SCRIPT: python x.py test
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror
-    MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z
+    MINGW_ARCHIVE: x86_64-6.2.0-release-posix-seh-rt_v5-rev1.7z
     MINGW_DIR: mingw64
 
   # 32/64 bit MSVC and GNU deployment
@@ -71,14 +60,14 @@ environment:
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja
     SCRIPT: python x.py dist
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror
-    MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z
+    MINGW_ARCHIVE: i686-6.2.0-release-posix-dwarf-rt_v5-rev1.7z
     MINGW_DIR: mingw32
     DEPLOY: 1
   - MSYS_BITS: 64
     SCRIPT: python x.py dist
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror
-    MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z
+    MINGW_ARCHIVE: x86_64-6.2.0-release-posix-seh-rt_v5-rev1.7z
     MINGW_DIR: mingw64
     DEPLOY: 1
 
diff --git a/cargo b/cargo
index c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28..03efb7fc8b0dbb54973ee1b6188f3faf14fffe36 160000 (submodule)
--- a/cargo
+++ b/cargo
@@ -1 +1 @@
-Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28
+Subproject commit 03efb7fc8b0dbb54973ee1b6188f3faf14fffe36
index 35b376d5f27b8c498d3691e720c9d3dcde558f45..c5ecc2236894cf0c5cb6cf2c4214249b2a648a2b 100755 (executable)
--- a/configure
+++ b/configure
@@ -479,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
 valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
 valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
 valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
+valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path"
 valopt nacl-cross-path  "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
 valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
 valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory"
@@ -746,6 +747,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK
 putvar CFG_ARM_LINUX_ANDROIDEABI_NDK
 putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK
 putvar CFG_I686_LINUX_ANDROID_NDK
+putvar CFG_X86_64_LINUX_ANDROID_NDK
 putvar CFG_NACL_CROSS_PATH
 putvar CFG_MANDIR
 putvar CFG_DOCDIR
diff --git a/rls b/rls
index 016cbc514cf44a2bd3fe806e8afa6b9c50287373..6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce 160000 (submodule)
--- a/rls
+++ b/rls
@@ -1 +1 @@
-Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373
+Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce
index f8f641060c442674f4d7b9a03b8d8bcde5008fec..8ab07e9e5b564498f1f80a8b23cbf8b2fc7bcdc3 100644 (file)
@@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) {
 pub fn cargotest(build: &Build, stage: u32, host: &str) {
     let ref compiler = Compiler::new(stage, host);
 
-    // Configure PATH to find the right rustc. NB. we have to use PATH
-    // and not RUSTC because the Cargo test suite has tests that will
-    // fail if rustc is not spelled `rustc`.
-    let path = build.sysroot(compiler).join("bin");
-    let old_path = ::std::env::var("PATH").expect("");
-    let sep = if cfg!(windows) { ";" } else {":" };
-    let ref newpath = format!("{}{}{}", path.display(), sep, old_path);
-
     // Note that this is a short, cryptic, and not scoped directory name. This
     // is currently to minimize the length of path on Windows where we otherwise
     // quickly run into path name limit constraints.
@@ -95,9 +87,35 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
     let _time = util::timeit();
     let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
     build.prepare_tool_cmd(compiler, &mut cmd);
-    build.run(cmd.env("PATH", newpath)
-                 .arg(&build.cargo)
-                 .arg(&out_dir));
+    build.run(cmd.arg(&build.cargo)
+                 .arg(&out_dir)
+                 .env("RUSTC", build.compiler_path(compiler))
+                 .env("RUSTDOC", build.rustdoc(compiler)))
+}
+
+/// Runs `cargo test` for `cargo` packaged with Rust.
+pub fn cargo(build: &Build, stage: u32, host: &str) {
+    let ref compiler = Compiler::new(stage, host);
+
+    // Configure PATH to find the right rustc. NB. we have to use PATH
+    // and not RUSTC because the Cargo test suite has tests that will
+    // fail if rustc is not spelled `rustc`.
+    let path = build.sysroot(compiler).join("bin");
+    let old_path = ::std::env::var("PATH").expect("");
+    let sep = if cfg!(windows) { ";" } else {":" };
+    let ref newpath = format!("{}{}{}", path.display(), sep, old_path);
+
+    let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
+    cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml"));
+
+    // Don't build tests dynamically, just a pain to work with
+    cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+
+    // Don't run cross-compile tests, we may not have cross-compiled libstd libs
+    // available.
+    cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
+
+    build.run(cargo.env("PATH", newpath));
 }
 
 /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
index bddd570a13d2640bfc26b8d63fb769e9f76fad95..cd87b27d4f1aa65650ce896b85ecf0411d4f0c08 100644 (file)
@@ -151,6 +151,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
         if !up_to_date(src_file, dst_file) {
             let mut cmd = Command::new(&compiler_path);
             build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
+                        .arg("--cfg").arg(format!("stage{}", compiler.stage))
                         .arg("--target").arg(target)
                         .arg("--emit=obj")
                         .arg("--out-dir").arg(dst_dir)
index 693114d01ad9c56fc04409c7d02706e888695e88..34fbc33d981afddfdc8af7662b85e2ed82a885d4 100644 (file)
@@ -570,6 +570,12 @@ macro_rules! check {
                                      .or_insert(Target::default());
                     target.ndk = Some(parse_configure_path(value));
                 }
+                "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => {
+                    let target = "x86_64-linux-android".to_string();
+                    let target = self.target_config.entry(target)
+                                     .or_insert(Target::default());
+                    target.ndk = Some(parse_configure_path(value));
+                }
                 "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
                     let path = parse_configure_path(value);
                     self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
index 4328c4e3f1d4c58126c11d62b428557f8b2845be..ada8d4df604e3550a0a9306a7352633c281a65c5 100644 (file)
@@ -254,7 +254,12 @@ pub fn debugger_scripts(build: &Build,
         install(&build.src.join("src/etc/").join(file), &dst, 0o644);
     };
     if host.contains("windows-msvc") {
-        // no debugger scripts
+        // windbg debugger scripts
+        install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
+            0o755);
+
+        cp_debugger_script("natvis/libcore.natvis");
+        cp_debugger_script("natvis/libcollections.natvis");
     } else {
         cp_debugger_script("debugger_pretty_printers_common.py");
 
index 5e046f41673e870235c6964e656c4f2b6a24ada0..bbfab3889500436c6c3ae47776e9b4025230f00d 100644 (file)
@@ -557,6 +557,19 @@ fn cargo(&self,
             cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
         }
 
+        // When being built Cargo will at some point call `nmake.exe` on Windows
+        // MSVC. Unfortunately `nmake` will read these two environment variables
+        // below and try to intepret them. We're likely being run, however, from
+        // MSYS `make` which uses the same variables.
+        //
+        // As a result, to prevent confusion and errors, we remove these
+        // variables from our environment to prevent passing MSYS make flags to
+        // nmake, causing it to blow up.
+        if cfg!(target_env = "msvc") {
+            cargo.env_remove("MAKE");
+            cargo.env_remove("MAKEFLAGS");
+        }
+
         // Environment variables *required* needed throughout the build
         //
         // FIXME: should update code to not require this env var
@@ -882,6 +895,13 @@ fn cflags(&self, target: &str) -> Vec<String> {
         if target.contains("apple-darwin") {
             base.push("-stdlib=libc++".into());
         }
+
+        // Work around an apparently bad MinGW / GCC optimization,
+        // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html
+        // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936
+        if target == "i686-pc-windows-gnu" {
+            base.push("-fno-omit-frame-pointer".into());
+        }
         return base
     }
 
index 457ac825832ce1d6ed6f4bb5b9bc719be6dcf524..a5df741e2bfc83965d5f6fbc722fd90dd6c030bb 100644 (file)
@@ -55,6 +55,7 @@ check:
 check-aux:
        $(Q)$(BOOTSTRAP) test \
                src/tools/cargotest \
+               cargo \
                src/test/pretty \
                src/test/run-pass/pretty \
                src/test/run-fail/pretty \
index 17902a39df1e82b4b76fa45034131fb67f630239..d811e1122c42fd0a15ff1dd6ea26e8dc2d00f501 100644 (file)
@@ -470,6 +470,10 @@ fn crate_rule<'a, 'b>(build: &'a Build,
          .dep(|s| s.name("librustc"))
          .host(true)
          .run(move |s| check::cargotest(build, s.stage, s.target));
+    rules.test("check-cargo", "cargo")
+         .dep(|s| s.name("tool-cargo"))
+         .host(true)
+         .run(move |s| check::cargo(build, s.stage, s.target));
     rules.test("check-tidy", "src/tools/tidy")
          .dep(|s| s.name("tool-tidy").stage(0))
          .default(true)
index 99c176aa820c733473a592781a91f0728dc5443d..28cc885ed30dabae3cc7fb5e14be7179a1713425 100644 (file)
@@ -36,9 +36,10 @@ RUN curl -o /usr/local/bin/sccache \
       chmod +x /usr/local/bin/sccache
 
 ENV TARGETS=arm-linux-androideabi
+ENV TARGETS=$TARGETS,armv7-linux-androideabi
 ENV TARGETS=$TARGETS,i686-linux-android
 ENV TARGETS=$TARGETS,aarch64-linux-android
-ENV TARGETS=$TARGETS,armv7-linux-androideabi
+ENV TARGETS=$TARGETS,x86_64-linux-android
 
 ENV RUST_CONFIGURE_ARGS \
       --target=$TARGETS \
@@ -46,6 +47,7 @@ ENV RUST_CONFIGURE_ARGS \
       --arm-linux-androideabi-ndk=/android/ndk-arm-9 \
       --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
       --i686-linux-android-ndk=/android/ndk-x86-9 \
-      --aarch64-linux-android-ndk=/android/ndk-aarch64
+      --aarch64-linux-android-ndk=/android/ndk-arm64-21 \
+      --x86_64-linux-android-ndk=/android/ndk-x86_64-21
 
 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
index 19c1b94e784c826a00f57ffe74c6b117645076c5..d3a2d31754543c0b95c64861062e4367976bb2ac 100644 (file)
@@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
         --platform=android-21 \
         --toolchain=aarch64-linux-android-4.9 \
-        --install-dir=/android/ndk-aarch64 \
+        --install-dir=/android/ndk-arm64-21 \
         --ndk-dir=/android/android-ndk-r11c \
         --arch=arm64
 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
@@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
         --install-dir=/android/ndk-x86-9 \
         --ndk-dir=/android/android-ndk-r11c \
         --arch=x86
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-21 \
+        --toolchain=x86_64-4.9 \
+        --install-dir=/android/ndk-x86_64-21 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=x86_64
 
 rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
index ffdb1d18a94ef8dd122222dc335bde25bc789a5e..cbbca23f6e3dbd5561927cdc48f4c9cd234b6e61 100644 (file)
@@ -27,10 +27,10 @@ WORKDIR /tmp
 COPY build-emscripten.sh /tmp/
 RUN ./build-emscripten.sh
 ENV PATH=$PATH:/tmp/emsdk_portable
-ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.1/build_tag-e1.37.1_32/bin
+ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.10/build_tag-e1.37.10_32/bin
 ENV PATH=$PATH:/tmp/emsdk_portable/node/4.1.1_32bit/bin
-ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.1
-ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.1
+ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.10
+ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.10
 
 ENV RUST_CONFIGURE_ARGS --target=asmjs-unknown-emscripten
 
index e39767357ad6301a56f463ec24d49a0ab7e97181..8d6a28f418bf955b8d75b049d33f49794630e538 100755 (executable)
@@ -49,5 +49,5 @@ chmod 755 emsdk_portable
 
 source emsdk_portable/emsdk_env.sh
 hide_output emsdk update
-hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit
-hide_output emsdk activate --build=Release sdk-tag-1.37.1-32bit
+hide_output emsdk install --build=Release sdk-tag-1.37.10-32bit
+hide_output emsdk activate --build=Release sdk-tag-1.37.10-32bit
index d30da544a8afc5d78391dee270bdf40e74a215d3..c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
+Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35
index 3fbf9f06d99f6fdbb49f3143f5327ff9fb65d35d..12daa24e857fcbfa62a4f292c1aab804936a57d9 100644 (file)
@@ -781,10 +781,11 @@ never_type : "!" ;
 ### Type parameter bounds
 
 ```antlr
+bound-list := bound | bound '+' bound-list '+' ?
 bound := ty_bound | lt_bound
 lt_bound := lifetime
-ty_bound := [?] [ for<lt_param_defs> ] simple_path
-bound-list := bound | bound '+' bound-list '+' ?
+ty_bound := ty_bound_noparen | (ty_bound_noparen)
+ty_bound_noparen := [?] [ for<lt_param_defs> ] simple_path
 ```
 
 ### Self types
index 1294c1a8c59e71e4d1798770fc7034333f9195eb..fd5b120e81faeceb8a0fd3e2898adeb5d24fead2 100644 (file)
@@ -32,16 +32,21 @@ nicknamed 'The Rust Bookshelf.'
 * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust.
 * [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book.
 
+Initially, documentation lands in the Unstable Book, and then, as part of the
+stabilization process, is moved into the Book, Nomicon, or Reference.
+
 Another few words about the reference: it is guaranteed to be accurate, but not
-complete. We now have a policy that all new features must be included in the
-reference before stabilization; however, we are still back-filling things that
-landed before then. That work is being tracked [here][38643].
+complete. We have a policy that features must have documentation to be stabilized,
+but we did not always have this policy, and so there are some stable things that
+are not yet in the reference. We're working on back-filling things that landed
+before this policy was put into place. That work is being tracked
+[here][refchecklist].
 
 [Rust Learning]: https://github.com/ctjhoa/rust-learning
 [Docs.rs]: https://docs.rs/
 [api]: std/index.html
 [ref]: reference/index.html
-[38643]: https://github.com/rust-lang/rust/issues/38643
+[refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9
 [err]: error-index.html
 [book]: book/index.html
 [nomicon]: nomicon/index.html
index 76196173b11e50a67b3535128e2a7dbb278e6123..2cb376301121821cabbd8c3fa0a6498d9e21c34b 100644 (file)
@@ -72,6 +72,7 @@
     - [proc_macro](language-features/proc-macro.md)
     - [quote](language-features/quote.md)
     - [relaxed_adts](language-features/relaxed-adts.md)
+    - [repr_align](language-features/repr-align.md)
     - [repr_simd](language-features/repr-simd.md)
     - [rustc_attrs](language-features/rustc-attrs.md)
     - [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md)
     - [alloc_system](library-features/alloc-system.md)
     - [alloc](library-features/alloc.md)
     - [as_c_str](library-features/as-c-str.md)
-    - [as_unsafe_cell](library-features/as-unsafe-cell.md)
     - [ascii_ctype](library-features/ascii-ctype.md)
-    - [binary_heap_extras](library-features/binary-heap-extras.md)
     - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md)
-    - [borrow_state](library-features/borrow-state.md)
     - [box_heap](library-features/box-heap.md)
     - [c_void_variant](library-features/c-void-variant.md)
     - [char_escape_debug](library-features/char-escape-debug.md)
     - [derive_clone_copy](library-features/derive-clone-copy.md)
     - [derive_eq](library-features/derive-eq.md)
     - [discriminant_value](library-features/discriminant-value.md)
-    - [enumset](library-features/enumset.md)
     - [error_type_id](library-features/error-type-id.md)
     - [exact_size_is_empty](library-features/exact-size-is-empty.md)
     - [fd](library-features/fd.md)
     - [fd_read](library-features/fd-read.md)
     - [fixed_size_array](library-features/fixed-size-array.md)
     - [float_bits_conv](library-features/float-bits-conv.md)
-    - [float_extras](library-features/float-extras.md)
     - [flt2dec](library-features/flt2dec.md)
     - [fmt_flags_align](library-features/fmt-flags-align.md)
     - [fmt_internals](library-features/fmt-internals.md)
     - [io_error_internals](library-features/io-error-internals.md)
     - [io](library-features/io.md)
     - [ip](library-features/ip.md)
-    - [is_unique](library-features/is-unique.md)
     - [iter_rfind](library-features/iter-rfind.md)
     - [libstd_io_internals](library-features/libstd-io-internals.md)
     - [libstd_sys_internals](library-features/libstd-sys-internals.md)
     - [linked_list_extras](library-features/linked-list-extras.md)
     - [lookup_host](library-features/lookup-host.md)
     - [manually_drop](library-features/manually-drop.md)
-    - [map_entry_recover_keys](library-features/map-entry-recover-keys.md)
+    - [more_io_inner_methods](library-features/more-io-inner-methods.md)
     - [mpsc_select](library-features/mpsc-select.md)
     - [n16](library-features/n16.md)
     - [never_type_impls](library-features/never-type-impls.md)
     - [rand](library-features/rand.md)
     - [range_contains](library-features/range-contains.md)
     - [raw](library-features/raw.md)
-    - [rc_would_unwrap](library-features/rc-would-unwrap.md)
     - [retain_hash_collection](library-features/retain-hash-collection.md)
     - [reverse_cmp_key](library-features/reverse-cmp-key.md)
     - [rt](library-features/rt.md)
     - [slice_rsplit](library-features/slice-rsplit.md)
     - [sort_internals](library-features/sort-internals.md)
     - [sort_unstable](library-features/sort-unstable.md)
+    - [splice](library-features/splice.md)
     - [step_by](library-features/step-by.md)
     - [step_trait](library-features/step-trait.md)
     - [str_checked_slicing](library-features/str-checked-slicing.md)
     - [windows_handle](library-features/windows-handle.md)
     - [windows_net](library-features/windows-net.md)
     - [windows_stdio](library-features/windows-stdio.md)
-    - [zero_one](library-features/zero-one.md)
->>>>>> Add top level sections to the Unstable Book.
diff --git a/src/doc/unstable-book/src/language-features/repr-align.md b/src/doc/unstable-book/src/language-features/repr-align.md
new file mode 100644 (file)
index 0000000..deea04f
--- /dev/null
@@ -0,0 +1,11 @@
+# `repr_align`
+
+The tracking issue for this feature is: [#33626]
+
+[#33626]: https://github.com/rust-lang/rust/issues/33626
+
+------------------------
+
+
+
+
diff --git a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md
deleted file mode 100644 (file)
index 79d7a7c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `as_unsafe_cell`
-
-The tracking issue for this feature is: [#27708]
-
-[#27708]: https://github.com/rust-lang/rust/issues/27708
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md
deleted file mode 100644 (file)
index aa535f3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `binary_heap_extras`
-
-The tracking issue for this feature is: [#28147]
-
-[#28147]: https://github.com/rust-lang/rust/issues/28147
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md
deleted file mode 100644 (file)
index 304b8df..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `borrow_state`
-
-The tracking issue for this feature is: [#27733]
-
-[#27733]: https://github.com/rust-lang/rust/issues/27733
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md
deleted file mode 100644 (file)
index 24c8d8f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `enumset`
-
-The tracking issue for this feature is: [#37966]
-
-[#37966]: https://github.com/rust-lang/rust/issues/37966
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md
deleted file mode 100644 (file)
index ff2d20a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `float_extras`
-
-The tracking issue for this feature is: [#27752]
-
-[#27752]: https://github.com/rust-lang/rust/issues/27752
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md
deleted file mode 100644 (file)
index 6070006..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `is_unique`
-
-The tracking issue for this feature is: [#28356]
-
-[#28356]: https://github.com/rust-lang/rust/issues/28356
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md
deleted file mode 100644 (file)
index 2d15aa0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# `map_entry_recover_keys`
-
-The tracking issue for this feature is: [#34285]
-
-[#34285]: https://github.com/rust-lang/rust/issues/34285
diff --git a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md
new file mode 100644 (file)
index 0000000..c84f40e
--- /dev/null
@@ -0,0 +1,11 @@
+# `more_io_inner_methods`
+
+The tracking issue for this feature is: [#41519]
+
+[#41519]: https://github.com/rust-lang/rust/issues/41519
+
+------------------------
+
+This feature enables several internal accessor methods on structures in
+`std::io` including `Take::{get_ref, get_mut}` and `Chain::{into_inner, get_ref,
+get_mut}`.
diff --git a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md
deleted file mode 100644 (file)
index 462387d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# `rc_would_unwrap`
-
-The tracking issue for this feature is: [#28356]
-
-[#28356]: https://github.com/rust-lang/rust/issues/28356
diff --git a/src/doc/unstable-book/src/library-features/splice.md b/src/doc/unstable-book/src/library-features/splice.md
new file mode 100644 (file)
index 0000000..ca7f78a
--- /dev/null
@@ -0,0 +1,24 @@
+# `splice`
+
+The tracking issue for this feature is: [#32310]
+
+[#32310]: https://github.com/rust-lang/rust/issues/32310
+
+------------------------
+
+The `splice()` method on `Vec` and `String` allows you to replace a range
+of values in a vector or string with another range of values, and returns
+the replaced values.
+
+A simple example:
+
+```rust
+#![feature(splice)]
+let mut s = String::from("α is alpha, β is beta");
+let beta_offset = s.find('β').unwrap_or(s.len());
+
+// Replace the range up until the β from the string
+let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
+assert_eq!(t, "α is alpha, ");
+assert_eq!(s, "Α is capital alpha; β is beta");
+```
\ No newline at end of file
diff --git a/src/doc/unstable-book/src/library-features/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md
deleted file mode 100644 (file)
index 4d1cf38..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# `zero_one`
-
-The tracking issue for this feature is: [#27739]
-
-[#27739]: https://github.com/rust-lang/rust/issues/27739
-
-------------------------
index 520a108da914cf965d6768a6d0f474fc5986f04e..52601cd96f80db4d0ee5c64bddcef0e39a517a80 100755 (executable)
@@ -17,7 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot`
 GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"
 
 # Run GDB with the additional arguments that load the pretty printers
-PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" gdb \
+# Set the environment variable `RUST_GDB` to overwrite the call to a
+# different/specific command (defaults to `gdb`).
+RUST_GDB="${RUST_GDB:-gdb}"
+PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \
   -d "$GDB_PYTHON_MODULE_DIRECTORY" \
   -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \
   "$@"
diff --git a/src/etc/rust-windbg.cmd b/src/etc/rust-windbg.cmd
new file mode 100644 (file)
index 0000000..4cdd6b9
--- /dev/null
@@ -0,0 +1,18 @@
+@echo off
+setlocal
+
+REM Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+REM file at the top-level directory of this distribution and at
+REM http://rust-lang.org/COPYRIGHT.
+REM
+REM Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+REM http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+REM <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+REM option. This file may not be copied, modified, or distributed
+REM except according to those terms.
+
+for /f "delims=" %%i in ('rustc --print=sysroot') do set rustc_sysroot=%%i
+
+set rust_etc=%rustc_sysroot%\lib\rustlib\etc
+
+windbg -c ".nvload %rust_etc%\libcore.natvis;.nvload %rust_etc%\libcollections.natvis;" %*
\ No newline at end of file
index 08a0b2a6d0080a2dfc053c78ea73f62900ac1a39..056af13016cf22797fb1624e2d0be77b8ffbd1d4 100644 (file)
@@ -16,7 +16,6 @@
             issue = "27700")]
 
 use core::{isize, usize};
-#[cfg(not(test))]
 use core::intrinsics::{min_align_of_val, size_of_val};
 
 #[allow(improper_ctypes)]
@@ -158,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     }
 }
 
-#[cfg(not(test))]
-#[lang = "box_free"]
+#[cfg_attr(not(test), lang = "box_free")]
 #[inline]
-unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
     let size = size_of_val(&*ptr);
     let align = min_align_of_val(&*ptr);
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
index 418a084da67878ff2c375b78cdf7153f70ed051c..fee0e1eb2608380389ae435becb44d565c0e7404 100644 (file)
@@ -87,6 +87,7 @@
 #![feature(needs_allocator)]
 #![feature(optin_builtin_traits)]
 #![feature(placement_in_syntax)]
+#![cfg_attr(stage0, feature(pub_restricted))]
 #![feature(shared)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
index fed718e9be4c6aa6ec5eba5c7b184a23c34e47dc..38dc914583517f9410e1f685fbe0b50e47286ec6 100644 (file)
 use core::ptr::{self, Shared};
 use core::convert::From;
 
-use heap::deallocate;
+use heap::{allocate, deallocate, box_free};
 use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
@@ -248,7 +248,6 @@ struct RcBox<T: ?Sized> {
     value: T,
 }
 
-
 /// A single-threaded reference-counting pointer.
 ///
 /// See the [module-level documentation](./index.html) for more details.
@@ -341,19 +340,6 @@ pub fn try_unwrap(this: Self) -> Result<T, Self> {
         }
     }
 
-    /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return
-    /// [`Ok`].
-    ///
-    /// [try_unwrap]: struct.Rc.html#method.try_unwrap
-    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    #[unstable(feature = "rc_would_unwrap",
-               reason = "just added for niche usecase",
-               issue = "28356")]
-    #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")]
-    pub fn would_unwrap(this: &Self) -> bool {
-        Rc::strong_count(&this) == 1
-    }
-
     /// Consumes the `Rc`, returning the wrapped pointer.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -438,6 +424,38 @@ pub fn __from_str(value: &str) -> Rc<str> {
     }
 }
 
+impl<T> Rc<[T]> {
+    /// Constructs a new `Rc<[T]>` from a `Box<[T]>`.
+    #[doc(hidden)]
+    #[unstable(feature = "rustc_private",
+               reason = "for internal use in rustc",
+               issue = "0")]
+    pub fn __from_array(value: Box<[T]>) -> Rc<[T]> {
+        unsafe {
+            let ptr: *mut RcBox<[T]> =
+                mem::transmute([mem::align_of::<RcBox<[T; 1]>>(), value.len()]);
+            // FIXME(custom-DST): creating this invalid &[T] is dubiously defined,
+            // we should have a better way of getting the size/align
+            // of a DST from its unsized part.
+            let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr));
+            let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]);
+
+            // Initialize the new RcBox.
+            ptr::write(&mut (*ptr).strong, Cell::new(1));
+            ptr::write(&mut (*ptr).weak, Cell::new(1));
+            ptr::copy_nonoverlapping(
+                value.as_ptr(),
+                &mut (*ptr).value as *mut [T] as *mut T,
+                value.len());
+
+            // Free the original allocation without freeing its (moved) contents.
+            box_free(Box::into_raw(value));
+
+            Rc { ptr: Shared::new(ptr as *const _) }
+        }
+    }
+}
+
 impl<T: ?Sized> Rc<T> {
     /// Creates a new [`Weak`][weak] pointer to this value.
     ///
@@ -501,11 +519,7 @@ pub fn strong_count(this: &Self) -> usize {
     ///
     /// [weak]: struct.Weak.html
     #[inline]
-    #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning",
-               issue = "28356")]
-    #[rustc_deprecated(since = "1.15.0",
-                       reason = "too niche; use `strong_count` and `weak_count` instead")]
-    pub fn is_unique(this: &Self) -> bool {
+    fn is_unique(this: &Self) -> bool {
         Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
     }
 
index 149c285a72a98d10a65aa2a2dc73b255601d24e4..7d972403f65db47dd923dc257487de5a5b08ab9a 100644 (file)
@@ -555,82 +555,6 @@ pub fn push(&mut self, item: T) {
         self.sift_up(0, old_len);
     }
 
-    /// Pushes an item onto the binary heap, then pops the greatest item off the queue in
-    /// an optimized fashion.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_extras)]
-    /// #![allow(deprecated)]
-    ///
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.push(1);
-    /// heap.push(5);
-    ///
-    /// assert_eq!(heap.push_pop(3), 5);
-    /// assert_eq!(heap.push_pop(9), 9);
-    /// assert_eq!(heap.len(), 2);
-    /// assert_eq!(heap.peek(), Some(&3));
-    /// ```
-    #[unstable(feature = "binary_heap_extras",
-               reason = "needs to be audited",
-               issue = "28147")]
-    #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
-    pub fn push_pop(&mut self, mut item: T) -> T {
-        match self.data.get_mut(0) {
-            None => return item,
-            Some(top) => {
-                if *top > item {
-                    swap(&mut item, top);
-                } else {
-                    return item;
-                }
-            }
-        }
-
-        self.sift_down(0);
-        item
-    }
-
-    /// Pops the greatest item off the binary heap, then pushes an item onto the queue in
-    /// an optimized fashion. The push is done regardless of whether the binary heap
-    /// was empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_extras)]
-    /// #![allow(deprecated)]
-    ///
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    ///
-    /// assert_eq!(heap.replace(1), None);
-    /// assert_eq!(heap.replace(3), Some(1));
-    /// assert_eq!(heap.len(), 1);
-    /// assert_eq!(heap.peek(), Some(&3));
-    /// ```
-    #[unstable(feature = "binary_heap_extras",
-               reason = "needs to be audited",
-               issue = "28147")]
-    #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
-    pub fn replace(&mut self, mut item: T) -> Option<T> {
-        if !self.is_empty() {
-            swap(&mut item, &mut self.data[0]);
-            self.sift_down(0);
-            Some(item)
-        } else {
-            self.push(item);
-            None
-        }
-    }
-
     /// Consumes the `BinaryHeap` and returns the underlying vector
     /// in arbitrary order.
     ///
@@ -1042,7 +966,7 @@ impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 /// An owning iterator over the elements of a `BinaryHeap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`]
+/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.BinaryHeap.html#method.into_iter
index fb0b852d10271a86a5c40e30145a3872b24fa8c9..d73c0254a74574221e1cd44d9ff12fe858cf588d 100644 (file)
@@ -298,7 +298,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 
 /// An owning iterator over the entries of a `BTreeMap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
+/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.BTreeMap.html#method.into_iter
@@ -2217,13 +2217,6 @@ pub fn key(&self) -> &K {
         self.handle.reborrow().into_kv().0
     }
 
-    /// Deprecated, renamed to `remove_entry`
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
-    pub fn remove_pair(self) -> (K, V) {
-        self.remove_entry()
-    }
-
     /// Take ownership of the key and value from the map.
     ///
     /// # Examples
index dfff44e30c5971aece4af110bde3f523a545066c..d32460da9392342e12834e28d1e5684956297b0a 100644 (file)
@@ -97,7 +97,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 /// An owning iterator over the items of a `BTreeSet`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
+/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`BTreeSet`]: struct.BTreeSet.html
@@ -138,7 +138,8 @@ pub struct Difference<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Difference")
-         .field(&self.clone())
+         .field(&self.a)
+         .field(&self.b)
          .finish()
     }
 }
@@ -160,7 +161,8 @@ pub struct SymmetricDifference<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("SymmetricDifference")
-         .field(&self.clone())
+         .field(&self.a)
+         .field(&self.b)
          .finish()
     }
 }
@@ -182,7 +184,8 @@ pub struct Intersection<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Intersection")
-         .field(&self.clone())
+         .field(&self.a)
+         .field(&self.b)
          .finish()
     }
 }
@@ -204,7 +207,8 @@ pub struct Union<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Union")
-         .field(&self.clone())
+         .field(&self.a)
+         .field(&self.b)
          .finish()
     }
 }
diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs
deleted file mode 100644 (file)
index ebee75d..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-// 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.
-
-//! A structure for holding a set of enum variants.
-//!
-//! This module defines a container which uses an efficient bit mask
-//! representation to hold C-like enum variants.
-
-#![unstable(feature = "enumset",
-            reason = "matches collection reform specification, \
-                      waiting for dust to settle",
-            issue = "37966")]
-#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")]
-#![allow(deprecated)]
-
-use core::marker;
-use core::fmt;
-use core::iter::{FromIterator, FusedIterator};
-use core::ops::{Sub, BitOr, BitAnd, BitXor};
-
-// FIXME(contentions): implement union family of methods? (general design may be
-// wrong here)
-
-/// A specialized set implementation to use enum types.
-///
-/// It is a logic error for an item to be modified in such a way that the
-/// transformation of the item to or from a `usize`, as determined by the
-/// `CLike` trait, changes while the item is in the set. This is normally only
-/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct EnumSet<E> {
-    // We must maintain the invariant that no bits are set
-    // for which no variant exists
-    bits: usize,
-    marker: marker::PhantomData<E>,
-}
-
-impl<E> Copy for EnumSet<E> {}
-
-impl<E> Clone for EnumSet<E> {
-    fn clone(&self) -> EnumSet<E> {
-        *self
-    }
-}
-
-impl<E: CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_set().entries(self).finish()
-    }
-}
-
-/// An interface for casting C-like enum to usize and back.
-/// A typically implementation is as below.
-///
-/// ```{rust,ignore}
-/// #[repr(usize)]
-/// enum Foo {
-///     A, B, C
-/// }
-///
-/// impl CLike for Foo {
-///     fn to_usize(&self) -> usize {
-///         *self as usize
-///     }
-///
-///     fn from_usize(v: usize) -> Foo {
-///         unsafe { mem::transmute(v) }
-///     }
-/// }
-/// ```
-pub trait CLike {
-    /// Converts a C-like enum to a `usize`.
-    fn to_usize(&self) -> usize;
-    /// Converts a `usize` to a C-like enum.
-    fn from_usize(usize) -> Self;
-}
-
-fn bit<E: CLike>(e: &E) -> usize {
-    use core::mem;
-    let value = e.to_usize();
-    let bits = mem::size_of::<usize>() * 8;
-    assert!(value < bits,
-            "EnumSet only supports up to {} variants.",
-            bits - 1);
-    1 << value
-}
-
-impl<E: CLike> EnumSet<E> {
-    /// Returns an empty `EnumSet`.
-    pub fn new() -> EnumSet<E> {
-        EnumSet {
-            bits: 0,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Returns the number of elements in the given `EnumSet`.
-    pub fn len(&self) -> usize {
-        self.bits.count_ones() as usize
-    }
-
-    /// Returns `true` if the `EnumSet` is empty.
-    pub fn is_empty(&self) -> bool {
-        self.bits == 0
-    }
-
-    pub fn clear(&mut self) {
-        self.bits = 0;
-    }
-
-    /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
-    pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
-        (self.bits & other.bits) == 0
-    }
-
-    /// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
-    pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
-        (self.bits & other.bits) == other.bits
-    }
-
-    /// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
-    pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
-        other.is_superset(self)
-    }
-
-    /// Returns the union of both `EnumSets`.
-    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits | e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Returns the intersection of both `EnumSets`.
-    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
-    pub fn insert(&mut self, e: E) -> bool {
-        let result = !self.contains(&e);
-        self.bits |= bit(&e);
-        result
-    }
-
-    /// Removes an enum from the EnumSet
-    pub fn remove(&mut self, e: &E) -> bool {
-        let result = self.contains(e);
-        self.bits &= !bit(e);
-        result
-    }
-
-    /// Returns `true` if an `EnumSet` contains a given enum.
-    pub fn contains(&self, e: &E) -> bool {
-        (self.bits & bit(e)) != 0
-    }
-
-    /// Returns an iterator over an `EnumSet`.
-    pub fn iter(&self) -> Iter<E> {
-        Iter::new(self.bits)
-    }
-}
-
-impl<E: CLike> Sub for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn sub(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & !e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitOr for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitor(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits | e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitAnd for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitand(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitXor for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits ^ e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-/// An iterator over an `EnumSet`
-pub struct Iter<E> {
-    index: usize,
-    bits: usize,
-    marker: marker::PhantomData<E>,
-}
-
-impl<E: fmt::Debug> fmt::Debug for Iter<E> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_tuple("Iter")
-         .field(&self.clone())
-         .finish()
-    }
-}
-
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
-impl<E> Clone for Iter<E> {
-    fn clone(&self) -> Iter<E> {
-        Iter {
-            index: self.index,
-            bits: self.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> Iter<E> {
-    fn new(bits: usize) -> Iter<E> {
-        Iter {
-            index: 0,
-            bits: bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> Iterator for Iter<E> {
-    type Item = E;
-
-    fn next(&mut self) -> Option<E> {
-        if self.bits == 0 {
-            return None;
-        }
-
-        while (self.bits & 1) == 0 {
-            self.index += 1;
-            self.bits >>= 1;
-        }
-        let elem = CLike::from_usize(self.index);
-        self.index += 1;
-        self.bits >>= 1;
-        Some(elem)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = self.bits.count_ones() as usize;
-        (exact, Some(exact))
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-impl<E: CLike> FusedIterator for Iter<E> {}
-
-impl<E: CLike> FromIterator<E> for EnumSet<E> {
-    fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> EnumSet<E> {
-        let mut ret = EnumSet::new();
-        ret.extend(iter);
-        ret
-    }
-}
-
-impl<'a, E> IntoIterator for &'a EnumSet<E>
-    where E: CLike
-{
-    type Item = E;
-    type IntoIter = Iter<E>;
-
-    fn into_iter(self) -> Iter<E> {
-        self.iter()
-    }
-}
-
-impl<E: CLike> Extend<E> for EnumSet<E> {
-    fn extend<I: IntoIterator<Item = E>>(&mut self, iter: I) {
-        for element in iter {
-            self.insert(element);
-        }
-    }
-}
-
-impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
-    fn extend<I: IntoIterator<Item = &'a E>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
-    }
-}
index c3db76e6c759d7134090993751fee36bdbad76fb..842f2f44fff9e8166652695f93e50fdfdf96ca9c 100644 (file)
@@ -90,9 +90,6 @@
 #[doc(no_inline)]
 pub use linked_list::LinkedList;
 #[doc(no_inline)]
-#[allow(deprecated)]
-pub use enum_set::EnumSet;
-#[doc(no_inline)]
 pub use vec_deque::VecDeque;
 #[doc(no_inline)]
 pub use string::String;
 pub mod binary_heap;
 mod btree;
 pub mod borrow;
-pub mod enum_set;
 pub mod fmt;
 pub mod linked_list;
 pub mod range;
index bfb03a5b23f1d29e11ffe6834da44f990904a28a..adfd91bec4893a32824e17f606ff911676338057 100644 (file)
@@ -75,7 +75,7 @@ pub struct Iter<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Iter")
-         .field(&self.clone())
+         .field(&self.len)
          .finish()
     }
 }
@@ -107,14 +107,15 @@ pub struct IterMut<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("IterMut")
-         .field(self.clone())
+         .field(&self.list)
+         .field(&self.len)
          .finish()
     }
 }
 
 /// An owning iterator over the elements of a `LinkedList`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`LinkedList`]
+/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.LinkedList.html#method.into_iter
@@ -129,7 +130,7 @@ pub struct IntoIter<T> {
 impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("IntoIter")
-         .field(self.clone())
+         .field(&self.list)
          .finish()
     }
 }
@@ -1128,7 +1129,7 @@ pub struct FrontPlace<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("FrontPlace")
-         .field(self.clone())
+         .field(&self.list)
          .finish()
     }
 }
@@ -1183,7 +1184,7 @@ pub struct BackPlace<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("BackPlace")
-         .field(self.clone())
+         .field(&self.list)
          .finish()
     }
 }
index 7c3c825cfd1f5dc309980514d74af6b7203b6b12..2eef132374e58b8a9f92c8edb37e5c101713da37 100644 (file)
@@ -1519,13 +1519,9 @@ fn to_owned(&self) -> Vec<T> {
         self.to_vec()
     }
 
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method
-    // definition, is not available. Since we don't require this method for testing purposes, I'll
-    // just stub it
-    // NB see the slice::hack module in slice.rs for more information
     #[cfg(test)]
     fn to_owned(&self) -> Vec<T> {
-        panic!("not available with cfg(test)")
+        hack::to_vec(self)
     }
 
     fn clone_into(&self, target: &mut Vec<T>) {
index 69dfb466d707ea38cc8868f9a0c20a8d4f173dc0..aa9628c535a997fb18939a2a7f66a85c61f10acb 100644 (file)
@@ -1317,7 +1317,7 @@ pub fn clear(&mut self) {
         self.vec.clear()
     }
 
-    /// Create a draining iterator that removes the specified range in the string
+    /// Creates a draining iterator that removes the specified range in the string
     /// and yields the removed chars.
     ///
     /// Note: The element range is removed even if the iterator is not
@@ -1383,6 +1383,71 @@ pub fn drain<R>(&mut self, range: R) -> Drain
         }
     }
 
+    /// Creates a splicing iterator that removes the specified range in the string,
+    /// replaces with the given string, and yields the removed chars.
+    /// The given string doesn’t need to be the same length as the range.
+    ///
+    /// Note: The element range is removed when the `Splice` is dropped,
+    /// even if the iterator is not consumed until the end.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the starting point or end point do not lie on a [`char`]
+    /// boundary, or if they're out of bounds.
+    ///
+    /// [`char`]: ../../std/primitive.char.html
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(splice)]
+    /// let mut s = String::from("α is alpha, β is beta");
+    /// let beta_offset = s.find('β').unwrap_or(s.len());
+    ///
+    /// // Replace the range up until the β from the string
+    /// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
+    /// assert_eq!(t, "α is alpha, ");
+    /// assert_eq!(s, "Α is capital alpha; β is beta");
+    /// ```
+    #[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+    pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
+        where R: RangeArgument<usize>
+    {
+        // Memory safety
+        //
+        // The String version of Splice does not have the memory safety issues
+        // of the vector version. The data is just plain bytes.
+        // Because the range removal happens in Drop, if the Splice iterator is leaked,
+        // the removal will not happen.
+        let len = self.len();
+        let start = match range.start() {
+             Included(&n) => n,
+             Excluded(&n) => n + 1,
+             Unbounded => 0,
+        };
+        let end = match range.end() {
+             Included(&n) => n + 1,
+             Excluded(&n) => n,
+             Unbounded => len,
+        };
+
+        // Take out two simultaneous borrows. The &mut String won't be accessed
+        // until iteration is over, in Drop.
+        let self_ptr = self as *mut _;
+        // slicing does the appropriate bounds checks
+        let chars_iter = self[start..end].chars();
+
+        Splice {
+            start: start,
+            end: end,
+            iter: chars_iter,
+            string: self_ptr,
+            replace_with: replace_with
+        }
+    }
+
     /// Converts this `String` into a `Box<str>`.
     ///
     /// This will drop any excess capacity.
@@ -2146,3 +2211,61 @@ fn next_back(&mut self) -> Option<char> {
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a> FusedIterator for Drain<'a> {}
+
+/// A splicing iterator for `String`.
+///
+/// This struct is created by the [`splice()`] method on [`String`]. See its
+/// documentation for more.
+///
+/// [`splice()`]: struct.String.html#method.splice
+/// [`String`]: struct.String.html
+#[derive(Debug)]
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+pub struct Splice<'a, 'b> {
+    /// Will be used as &'a mut String in the destructor
+    string: *mut String,
+    /// Start of part to remove
+    start: usize,
+    /// End of part to remove
+    end: usize,
+    /// Current remaining range to remove
+    iter: Chars<'a>,
+    replace_with: &'b str,
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, 'b> Drop for Splice<'a, 'b> {
+    fn drop(&mut self) {
+        unsafe {
+            let vec = (*self.string).as_mut_vec();
+            vec.splice(self.start..self.end, self.replace_with.bytes());
+        }
+    }
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, 'b> Iterator for Splice<'a, 'b> {
+    type Item = char;
+
+    #[inline]
+    fn next(&mut self) -> Option<char> {
+        self.iter.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
+    #[inline]
+    fn next_back(&mut self) -> Option<char> {
+        self.iter.next_back()
+    }
+}
index d284937a9e676a0a56ce4824c3b8abb2dd62f8b1..af18cddaddb013050ce91c6c98e32e06c6ba2ebe 100644 (file)
@@ -152,36 +152,6 @@ fn test_push_unique() {
     assert!(*heap.peek().unwrap() == box 103);
 }
 
-#[test]
-#[allow(deprecated)]
-fn test_push_pop() {
-    let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(6), 6);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(0), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(4), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(1), 4);
-    assert_eq!(heap.len(), 5);
-}
-
-#[test]
-#[allow(deprecated)]
-fn test_replace() {
-    let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(6).unwrap(), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(0).unwrap(), 6);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(4).unwrap(), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(1).unwrap(), 4);
-    assert_eq!(heap.len(), 5);
-}
-
 fn check_to_vec(mut data: Vec<i32>) {
     let heap = BinaryHeap::from(data.clone());
     let mut v = heap.clone().into_vec();
@@ -227,13 +197,6 @@ fn test_empty_peek_mut() {
     assert!(empty.peek_mut().is_none());
 }
 
-#[test]
-#[allow(deprecated)]
-fn test_empty_replace() {
-    let mut heap = BinaryHeap::new();
-    assert!(heap.replace(5).is_none());
-}
-
 #[test]
 fn test_from_iter() {
     let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
index 618eb386c0f4c88887b1baab32c2cc553ce64a69..eae3bf3915f60d1f40f30ab3203aafcc1363d4cf 100644 (file)
@@ -10,7 +10,6 @@
 
 #![deny(warnings)]
 
-#![feature(binary_heap_extras)]
 #![feature(binary_heap_peek_mut_pop)]
 #![feature(box_syntax)]
 #![feature(inclusive_range_syntax)]
@@ -21,6 +20,7 @@
 #![feature(pattern)]
 #![feature(placement_in_syntax)]
 #![feature(rand)]
+#![feature(splice)]
 #![feature(step_by)]
 #![feature(str_escape)]
 #![feature(test)]
index 2f021b9935d6abc9b74daea6fdba81de54e9e765..b1731b2a5dcaa486b8e189e97b88dbdf23b9e85f 100644 (file)
@@ -419,6 +419,69 @@ fn test_drain() {
     assert_eq!(t, "");
 }
 
+#[test]
+fn test_splice() {
+    let mut s = "Hello, world!".to_owned();
+    let t: String = s.splice(7..12, "世界").collect();
+    assert_eq!(s, "Hello, 世界!");
+    assert_eq!(t, "world");
+}
+
+#[test]
+#[should_panic]
+fn test_splice_char_boundary() {
+    let mut s = "Hello, 世界!".to_owned();
+    s.splice(..8, "");
+}
+
+#[test]
+fn test_splice_inclusive_range() {
+    let mut v = String::from("12345");
+    let t: String = v.splice(2...3, "789").collect();
+    assert_eq!(v, "127895");
+    assert_eq!(t, "34");
+    let t2: String = v.splice(1...2, "A").collect();
+    assert_eq!(v, "1A895");
+    assert_eq!(t2, "27");
+}
+
+#[test]
+#[should_panic]
+fn test_splice_out_of_bounds() {
+    let mut s = String::from("12345");
+    s.splice(5..6, "789");
+}
+
+#[test]
+#[should_panic]
+fn test_splice_inclusive_out_of_bounds() {
+    let mut s = String::from("12345");
+    s.splice(5...5, "789");
+}
+
+#[test]
+fn test_splice_empty() {
+    let mut s = String::from("12345");
+    let t: String = s.splice(1..2, "").collect();
+    assert_eq!(s, "1345");
+    assert_eq!(t, "2");
+}
+
+#[test]
+fn test_splice_unbounded() {
+    let mut s = String::from("12345");
+    let t: String = s.splice(.., "").collect();
+    assert_eq!(s, "");
+    assert_eq!(t, "12345");
+}
+
+#[test]
+fn test_splice_forget() {
+    let mut s = String::from("12345");
+    ::std::mem::forget(s.splice(2..4, "789"));
+    assert_eq!(s, "12345");
+}
+
 #[test]
 fn test_extend_ref() {
     let mut a = "foo".to_string();
index 64c76142b59d660ca8d975a23da5aa7040c8f2aa..29f18274962fe04e6c3a517370c401d610f711ca 100644 (file)
@@ -579,6 +579,69 @@ fn test_drain_inclusive_out_of_bounds() {
     v.drain(5...5);
 }
 
+#[test]
+fn test_splice() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let a = [10, 11, 12];
+    v.splice(2..4, a.iter().cloned());
+    assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
+    v.splice(1..3, Some(20));
+    assert_eq!(v, &[1, 20, 11, 12, 5]);
+}
+
+#[test]
+fn test_splice_inclusive_range() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let a = [10, 11, 12];
+    let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect();
+    assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
+    assert_eq!(t1, &[3, 4]);
+    let t2: Vec<_> = v.splice(1...2, Some(20)).collect();
+    assert_eq!(v, &[1, 20, 11, 12, 5]);
+    assert_eq!(t2, &[2, 10]);
+}
+
+#[test]
+#[should_panic]
+fn test_splice_out_of_bounds() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let a = [10, 11, 12];
+    v.splice(5..6, a.iter().cloned());
+}
+
+#[test]
+#[should_panic]
+fn test_splice_inclusive_out_of_bounds() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let a = [10, 11, 12];
+    v.splice(5...5, a.iter().cloned());
+}
+
+#[test]
+fn test_splice_items_zero_sized() {
+    let mut vec = vec![(), (), ()];
+    let vec2 = vec![];
+    let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect();
+    assert_eq!(vec, &[(), ()]);
+    assert_eq!(t, &[()]);
+}
+
+#[test]
+fn test_splice_unbounded() {
+    let mut vec = vec![1, 2, 3, 4, 5];
+    let t: Vec<_> = vec.splice(.., None).collect();
+    assert_eq!(vec, &[]);
+    assert_eq!(t, &[1, 2, 3, 4, 5]);
+}
+
+#[test]
+fn test_splice_forget() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let a = [10, 11, 12];
+    ::std::mem::forget(v.splice(2..4, a.iter().cloned()));
+    assert_eq!(v, &[1, 2]);
+}
+
 #[test]
 fn test_into_boxed_slice() {
     let xs = vec![1, 2, 3];
index 6deb87ae772049b0c793df969cbd9d69107980b0..fc5de70e98387ed7583c7bc9308e393ceec2aa76 100644 (file)
 /// removed data to be erased for security purposes. Even if you drop a `Vec`, its
 /// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
 /// first, that may not actually happen because the optimizer does not consider
-/// this a side-effect that must be preserved.
+/// this a side-effect that must be preserved. There is one case which we will
+/// not break, however: using `unsafe` code to write to the excess capacity,
+/// and then increasing the length to match, is always valid.
 ///
 /// `Vec` does not currently guarantee the order in which elements are dropped
 /// (the order has changed in the past, and may change again).
@@ -1057,13 +1059,13 @@ unsafe fn append_elements(&mut self, other: *const [T]) {
         self.len += count;
     }
 
-    /// Create a draining iterator that removes the specified range in the vector
+    /// Creates a draining iterator that removes the specified range in the vector
     /// and yields the removed items.
     ///
     /// Note 1: The element range is removed even if the iterator is only
     /// partially consumed or not consumed at all.
     ///
-    /// Note 2: It is unspecified how many elements are removed from the vector,
+    /// Note 2: It is unspecified how many elements are removed from the vector
     /// if the `Drain` value is leaked.
     ///
     /// # Panics
@@ -1147,7 +1149,8 @@ pub fn clear(&mut self) {
         self.truncate(0)
     }
 
-    /// Returns the number of elements in the vector.
+    /// Returns the number of elements in the vector, also referred to
+    /// as its 'length'.
     ///
     /// # Examples
     ///
@@ -1845,6 +1848,54 @@ fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
             }
         }
     }
+
+    /// Creates a splicing iterator that replaces the specified range in the vector
+    /// with the given `replace_with` iterator and yields the removed items.
+    /// `replace_with` does not need to be the same length as `range`.
+    ///
+    /// Note 1: The element range is removed even if the iterator is not
+    /// consumed until the end.
+    ///
+    /// Note 2: It is unspecified how many elements are removed from the vector,
+    /// if the `Splice` value is leaked.
+    ///
+    /// Note 3: The input iterator `replace_with` is only consumed
+    /// when the `Splice` value is dropped.
+    ///
+    /// Note 4: This is optimal if:
+    ///
+    /// * The tail (elements in the vector after `range`) is empty,
+    /// * or `replace_with` yields fewer elements than `range`’s length
+    /// * or the lower bound of its `size_hint()` is exact.
+    ///
+    /// Otherwise, a temporary vector is allocated and the tail is moved twice.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the starting point is greater than the end point or if
+    /// the end point is greater than the length of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(splice)]
+    /// let mut v = vec![1, 2, 3];
+    /// let new = [7, 8];
+    /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+    /// assert_eq!(v, &[7, 8, 3]);
+    /// assert_eq!(u, &[1, 2]);
+    /// ```
+    #[inline]
+    #[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+    pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<I::IntoIter>
+        where R: RangeArgument<usize>, I: IntoIterator<Item=T>
+    {
+        Splice {
+            drain: self.drain(range),
+            replace_with: replace_with.into_iter(),
+        }
+    }
+
 }
 
 #[stable(feature = "extend_ref", since = "1.2.0")]
@@ -1984,6 +2035,18 @@ fn from(s: &'a [T]) -> Vec<T> {
     }
 }
 
+#[stable(feature = "vec_from_mut", since = "1.21.0")]
+impl<'a, T: Clone> From<&'a mut [T]> for Vec<T> {
+    #[cfg(not(test))]
+    fn from(s: &'a mut [T]) -> Vec<T> {
+        s.to_vec()
+    }
+    #[cfg(test)]
+    fn from(s: &'a mut [T]) -> Vec<T> {
+        ::slice::to_vec(s)
+    }
+}
+
 #[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
 impl<'a, T> From<Cow<'a, [T]>> for Vec<T> where [T]: ToOwned<Owned=Vec<T>> {
     fn from(s: Cow<'a, [T]>) -> Vec<T> {
@@ -2344,3 +2407,125 @@ unsafe fn finalize(mut self) -> &'a mut T {
         &mut *ptr
     }
 }
+
+
+/// A splicing iterator for `Vec`.
+///
+/// This struct is created by the [`splice()`] method on [`Vec`]. See its
+/// documentation for more.
+///
+/// [`splice()`]: struct.Vec.html#method.splice
+/// [`Vec`]: struct.Vec.html
+#[derive(Debug)]
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+pub struct Splice<'a, I: Iterator + 'a> {
+    drain: Drain<'a, I::Item>,
+    replace_with: I,
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, I: Iterator> Iterator for Splice<'a, I> {
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.drain.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.drain.size_hint()
+    }
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.drain.next_back()
+    }
+}
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {}
+
+
+#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
+impl<'a, I: Iterator> Drop for Splice<'a, I> {
+    fn drop(&mut self) {
+        // exhaust drain first
+        while let Some(_) = self.drain.next() {}
+
+
+        unsafe {
+            if self.drain.tail_len == 0 {
+                let vec = &mut *self.drain.vec.as_mut_ptr();
+                vec.extend(self.replace_with.by_ref());
+                return
+            }
+
+            // First fill the range left by drain().
+            if !self.drain.fill(&mut self.replace_with) {
+                return
+            }
+
+            // There may be more elements. Use the lower bound as an estimate.
+            // FIXME: Is the upper bound a better guess? Or something else?
+            let (lower_bound, _upper_bound) = self.replace_with.size_hint();
+            if lower_bound > 0  {
+                self.drain.move_tail(lower_bound);
+                if !self.drain.fill(&mut self.replace_with) {
+                    return
+                }
+            }
+
+            // Collect any remaining elements.
+            // This is a zero-length vector which does not allocate if `lower_bound` was exact.
+            let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
+            // Now we have an exact count.
+            if collected.len() > 0 {
+                self.drain.move_tail(collected.len());
+                let filled = self.drain.fill(&mut collected);
+                debug_assert!(filled);
+                debug_assert_eq!(collected.len(), 0);
+            }
+        }
+        // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
+    }
+}
+
+/// Private helper methods for `Splice::drop`
+impl<'a, T> Drain<'a, T> {
+    /// The range from `self.vec.len` to `self.tail_start` contains elements
+    /// that have been moved out.
+    /// Fill that range as much as possible with new elements from the `replace_with` iterator.
+    /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.)
+    unsafe fn fill<I: Iterator<Item=T>>(&mut self, replace_with: &mut I) -> bool {
+        let vec = &mut *self.vec.as_mut_ptr();
+        let range_start = vec.len;
+        let range_end = self.tail_start;
+        let range_slice = slice::from_raw_parts_mut(
+            vec.as_mut_ptr().offset(range_start as isize),
+            range_end - range_start);
+
+        for place in range_slice {
+            if let Some(new_item) = replace_with.next() {
+                ptr::write(place, new_item);
+                vec.len += 1;
+            } else {
+                return false
+            }
+        }
+        true
+    }
+
+    /// Make room for inserting more elements before the tail.
+    unsafe fn move_tail(&mut self, extra_capacity: usize) {
+        let vec = &mut *self.vec.as_mut_ptr();
+        let used_capacity = self.tail_start + self.tail_len;
+        vec.buf.reserve(used_capacity, extra_capacity);
+
+        let new_tail_start = self.tail_start + extra_capacity;
+        let src = vec.as_ptr().offset(self.tail_start as isize);
+        let dst = vec.as_mut_ptr().offset(new_tail_start as isize);
+        ptr::copy(src, dst, self.tail_len);
+        self.tail_start = new_tail_start;
+    }
+}
index 2a73a78adbe5f2c7459c487a30dff26a8f7e8b03..079d3acf3764ac159c9014b043f7c14380da2781 100644 (file)
@@ -1913,7 +1913,9 @@ pub struct Iter<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Iter")
-         .field(&self.clone())
+         .field(&self.ring)
+         .field(&self.tail)
+         .field(&self.head)
          .finish()
     }
 }
@@ -2000,7 +2002,9 @@ pub struct IterMut<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("IterMut")
-         .field(&self.clone())
+         .field(&self.ring)
+         .field(&self.tail)
+         .field(&self.head)
          .finish()
     }
 }
@@ -2066,7 +2070,7 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 /// An owning iterator over the elements of a `VecDeque`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`VecDeque`]
+/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.VecDeque.html#method.into_iter
@@ -2081,7 +2085,7 @@ pub struct IntoIter<T> {
 impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("IntoIter")
-         .field(&self.clone())
+         .field(&self.inner)
          .finish()
     }
 }
@@ -2139,7 +2143,9 @@ pub struct Drain<'a, T: 'a> {
 impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Drain")
-         .field(&self.clone())
+         .field(&self.after_tail)
+         .field(&self.after_head)
+         .field(&self.iter)
          .finish()
     }
 }
index bcd3a92dd430548704981736f5c8fe9ca153c21d..8fe79057bd81738bdca8054bcdf6331fc78f052a 100644 (file)
@@ -293,6 +293,12 @@ fn main() {
     }
 
     if target.contains("arm") && !target.contains("ios") {
+        // (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by
+        // default, we don't want Thumb 2 since it isn't supported on some
+        // devices, so disable thumb entirely.
+        // Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492
+        cfg.define("__ARM_ARCH_ISA_THUMB", Some("0"));
+
         sources.extend(&["arm/aeabi_cdcmp.S",
                          "arm/aeabi_cdcmpeq_check_nan.c",
                          "arm/aeabi_cfcmp.S",
index 0186d9727828d0420a0d048d0bcd8037bf470901..f62057b3a52d08c4294fe00c166755b86b6b7b64 100644 (file)
@@ -310,26 +310,6 @@ pub const fn new(value: T) -> Cell<T> {
         }
     }
 
-    /// Returns a reference to the underlying `UnsafeCell`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(as_unsafe_cell)]
-    ///
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// let uc = c.as_unsafe_cell();
-    /// ```
-    #[inline]
-    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
-    pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
-        &self.value
-    }
-
     /// Returns a raw pointer to the underlying data in this cell.
     ///
     /// # Examples
@@ -480,20 +460,6 @@ pub struct RefCell<T: ?Sized> {
     value: UnsafeCell<T>,
 }
 
-/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "borrow_state", issue = "27733")]
-#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
-#[allow(deprecated)]
-pub enum BorrowState {
-    /// The cell is currently being read, there is at least one active `borrow`.
-    Reading,
-    /// The cell is currently being written to, there is an active `borrow_mut`.
-    Writing,
-    /// There are no outstanding borrows on this cell.
-    Unused,
-}
-
 /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow).
 #[stable(feature = "try_borrow", since = "1.13.0")]
 pub struct BorrowError {
@@ -582,38 +548,6 @@ pub fn into_inner(self) -> T {
 }
 
 impl<T: ?Sized> RefCell<T> {
-    /// Query the current state of this `RefCell`
-    ///
-    /// The returned value can be dispatched on to determine if a call to
-    /// `borrow` or `borrow_mut` would succeed.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(borrow_state)]
-    ///
-    /// use std::cell::{BorrowState, RefCell};
-    ///
-    /// let c = RefCell::new(5);
-    ///
-    /// match c.borrow_state() {
-    ///     BorrowState::Writing => println!("Cannot be borrowed"),
-    ///     BorrowState::Reading => println!("Cannot be borrowed mutably"),
-    ///     BorrowState::Unused => println!("Can be borrowed (mutably as well)"),
-    /// }
-    /// ```
-    #[unstable(feature = "borrow_state", issue = "27733")]
-    #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
-    #[allow(deprecated)]
-    #[inline]
-    pub fn borrow_state(&self) -> BorrowState {
-        match self.borrow.get() {
-            WRITING => BorrowState::Writing,
-            UNUSED => BorrowState::Unused,
-            _ => BorrowState::Reading,
-        }
-    }
-
     /// Immutably borrows the wrapped value.
     ///
     /// The borrow lasts until the returned `Ref` exits scope. Multiple
@@ -769,29 +703,6 @@ pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError> {
         }
     }
 
-    /// Returns a reference to the underlying `UnsafeCell`.
-    ///
-    /// This can be used to circumvent `RefCell`'s safety checks.
-    ///
-    /// This function is `unsafe` because `UnsafeCell`'s field is public.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(as_unsafe_cell)]
-    ///
-    /// use std::cell::RefCell;
-    ///
-    /// let c = RefCell::new(5);
-    /// let c = unsafe { c.as_unsafe_cell() };
-    /// ```
-    #[inline]
-    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
-    pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
-        &self.value
-    }
-
     /// Returns a raw pointer to the underlying data in this cell.
     ///
     /// # Examples
@@ -814,6 +725,15 @@ pub fn as_ptr(&self) -> *mut T {
     /// This call borrows `RefCell` mutably (at compile-time) so there is no
     /// need for dynamic checks.
     ///
+    /// However be cautious: this method expects `self` to be mutable, which is
+    /// generally not the case when using a `RefCell`. Take a look at the
+    /// [`borrow_mut`] method instead if `self` isn't mutable.
+    ///
+    /// Also, please be aware that this method is only for special circumstances and is usually
+    /// not you want. In case of doubt, use [`borrow_mut`] instead.
+    ///
+    /// [`borrow_mut`]: #method.borrow_mut
+    ///
     /// # Examples
     ///
     /// ```
index 0b0f831f093b0ecc761a60ce18a595397d3cce53..084736685e3a7f49bf23e4db4e3f7c97eec02fc9 100644 (file)
@@ -17,8 +17,8 @@
 //! Like many traits, these are often used as bounds for generic functions, to
 //! support arguments of multiple types.
 //!
-//! - Impl the `As*` traits for reference-to-reference conversions
-//! - Impl the [`Into`] trait when you want to consume the value in the conversion
+//! - Implement the `As*` traits for reference-to-reference conversions
+//! - Implement the [`Into`] trait when you want to consume the value in the conversion
 //! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions
 //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the
 //!   conversion to fail
 //! As a library author, you should prefer implementing [`From<T>`][`From`] or
 //! [`TryFrom<T>`][`TryFrom`] rather than [`Into<U>`][`Into`] or [`TryInto<U>`][`TryInto`],
 //! as [`From`] and [`TryFrom`] provide greater flexibility and offer
-//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation
-//! in the standard library.
+//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a
+//! blanket implementation in the standard library.
 //!
-//! # Generic impl
+//! # Generic Implementations
 //!
 //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference
 //! - [`From`]`<U> for T` implies [`Into`]`<T> for U`
 //! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> for U`
-//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()`
-//!   themselves and `from()` themselves
+//! - [`From`] and [`Into`] are reflexive, which means that all types can
+//!   `into` themselves and `from` themselves
 //!
 //! See each trait for usage examples.
 //!
 
 use str::FromStr;
 
-/// A cheap, reference-to-reference conversion.
+/// A cheap reference-to-reference conversion. Used to convert a value to a
+/// reference value within generic code.
 ///
-/// `AsRef` is very similar to, but different than, [`Borrow`]. See
-/// [the book][book] for more.
+/// `AsRef` is very similar to, but serves a slightly different purpose than,
+/// [`Borrow`].
+///
+/// `AsRef` is to be used when wishing to convert to a reference of another
+/// type.
+/// `Borrow` is more related to the notion of taking the reference. It is
+/// useful when wishing to abstract over the type of reference
+/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated
+/// in the same manner.
+///
+/// The key difference between the two traits is the intention:
+///
+/// - Use `AsRef` when goal is to simply convert into a reference
+/// - Use `Borrow` when goal is related to writing code that is agnostic to the
+///   type of borrow and if is reference or value
+///
+/// See [the book][book] for a more detailed comparison.
 ///
 /// [book]: ../../book/borrow-and-asref.html
 /// [`Borrow`]: ../../std/borrow/trait.Borrow.html
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
-/// returns an [`Option<T>`] or a [`Result<T, E>`].
+/// **Note: this trait must not fail**. If the conversion can fail, use a
+/// dedicated method which returns an [`Option<T>`] or a [`Result<T, E>`].
 ///
 /// [`Option<T>`]: ../../std/option/enum.Option.html
 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
 ///
+/// # Generic Implementations
+///
+/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
+///   reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
+///   `&mut Foo` or `&&mut Foo`)
+///
 /// # Examples
 ///
 /// Both [`String`] and `&str` implement `AsRef<str>`:
 /// is_hello(s);
 /// ```
 ///
-/// # Generic Impls
-///
-/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
-/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
-///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsRef<T: ?Sized> {
     /// Performs the conversion.
@@ -96,12 +113,21 @@ pub trait AsRef<T: ?Sized> {
 
 /// A cheap, mutable reference-to-mutable reference conversion.
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
-/// returns an [`Option<T>`] or a [`Result<T, E>`].
+/// This trait is similar to `AsRef` but used for converting between mutable
+/// references.
+///
+/// **Note: this trait must not fail**. If the conversion can fail, use a
+/// dedicated method which returns an [`Option<T>`] or a [`Result<T, E>`].
 ///
 /// [`Option<T>`]: ../../std/option/enum.Option.html
 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
 ///
+/// # Generic Implementations
+///
+/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
+///   reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
+///   `&mut Foo` or `&&mut Foo`)
+///
 /// # Examples
 ///
 /// [`Box<T>`] implements `AsMut<T>`:
@@ -118,10 +144,6 @@ pub trait AsRef<T: ?Sized> {
 /// assert_eq!(*boxed_num, 1);
 /// ```
 ///
-/// # Generic Impls
-///
-/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
-/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsMut<T: ?Sized> {
@@ -130,14 +152,22 @@ pub trait AsMut<T: ?Sized> {
     fn as_mut(&mut self) -> &mut T;
 }
 
-/// A conversion that consumes `self`, which may or may not be expensive.
+/// A conversion that consumes `self`, which may or may not be expensive. The
+/// reciprocal of [`From`][From].
+///
+/// **Note: this trait must not fail**. If the conversion can fail, use
+/// [`TryInto`] or a dedicated method which returns an [`Option<T>`] or a
+/// [`Result<T, E>`].
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated
-/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
+/// Library authors should not directly implement this trait, but should prefer
+/// implementing the [`From`][From] trait, which offers greater flexibility and
+/// provides an equivalent `Into` implementation for free, thanks to a blanket
+/// implementation in the standard library.
 ///
-/// Library authors should not directly implement this trait, but should prefer implementing
-/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into`
-/// implementation for free, thanks to a blanket implementation in the standard library.
+/// # Generic Implementations
+///
+/// - [`From<T>`][From]` for U` implies `Into<U> for T`
+/// - [`into`] is reflexive, which means that `Into<T> for T` is implemented
 ///
 /// # Examples
 ///
@@ -153,11 +183,6 @@ pub trait AsMut<T: ?Sized> {
 /// is_hello(s);
 /// ```
 ///
-/// # Generic Impls
-///
-/// - [`From<T>`][From]` for U` implies `Into<U> for T`
-/// - [`into`] is reflexive, which means that `Into<T> for T` is implemented
-///
 /// [`TryInto`]: trait.TryInto.html
 /// [`Option<T>`]: ../../std/option/enum.Option.html
 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
@@ -171,10 +196,31 @@ pub trait Into<T>: Sized {
     fn into(self) -> T;
 }
 
-/// Construct `Self` via a conversion.
+/// Simple and safe type conversions in to `Self`. It is the reciprocal of
+/// `Into`.
+///
+/// This trait is useful when performing error handling as described by
+/// [the book][book] and is closely related to the `?` operator.
+///
+/// When constructing a function that is capable of failing the return type
+/// will generally be of the form `Result<T, E>`.
+///
+/// The `From` trait allows for simplification of error handling by providing a
+/// means of returning a single error type that encapsulates numerous possible
+/// erroneous situations.
+///
+/// This trait is not limited to error handling, rather the general case for
+/// this trait would be in any type conversions to have an explicit definition
+/// of how they are performed.
+///
+/// **Note: this trait must not fail**. If the conversion can fail, use
+/// [`TryFrom`] or a dedicated method which returns an [`Option<T>`] or a
+/// [`Result<T, E>`].
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated
-/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
+/// # Generic Implementations
+///
+/// - `From<T> for U` implies [`Into<U>`]` for T`
+/// - [`from`] is reflexive, which means that `From<T> for T` is implemented
 ///
 /// # Examples
 ///
@@ -186,10 +232,38 @@ pub trait Into<T>: Sized {
 ///
 /// assert_eq!(string, other_string);
 /// ```
-/// # Generic impls
 ///
-/// - `From<T> for U` implies [`Into<U>`]` for T`
-/// - [`from`] is reflexive, which means that `From<T> for T` is implemented
+/// An example usage for error handling:
+///
+/// ```
+/// use std::io::{self, Read};
+/// use std::num;
+///
+/// enum CliError {
+///     IoError(io::Error),
+///     ParseError(num::ParseIntError),
+/// }
+///
+/// impl From<io::Error> for CliError {
+///     fn from(error: io::Error) -> Self {
+///         CliError::IoError(error)
+///     }
+/// }
+///
+/// impl From<num::ParseIntError> for CliError {
+///     fn from(error: num::ParseIntError) -> Self {
+///         CliError::ParseError(error)
+///     }
+/// }
+///
+/// fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
+///     let mut file = std::fs::File::open("test")?;
+///     let mut contents = String::new();
+///     file.read_to_string(&mut contents)?;
+///     let num: i32 = contents.trim().parse()?;
+///     Ok(num)
+/// }
+/// ```
 ///
 /// [`TryFrom`]: trait.TryFrom.html
 /// [`Option<T>`]: ../../std/option/enum.Option.html
@@ -197,6 +271,7 @@ pub trait Into<T>: Sized {
 /// [`String`]: ../../std/string/struct.String.html
 /// [`Into<U>`]: trait.Into.html
 /// [`from`]: trait.From.html#tymethod.from
+/// [book]: ../../book/error-handling.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait From<T>: Sized {
     /// Performs the conversion.
@@ -204,11 +279,13 @@ pub trait From<T>: Sized {
     fn from(T) -> Self;
 }
 
-/// An attempted conversion that consumes `self`, which may or may not be expensive.
+/// An attempted conversion that consumes `self`, which may or may not be
+/// expensive.
 ///
-/// Library authors should not directly implement this trait, but should prefer implementing
-/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto`
-/// implementation for free, thanks to a blanket implementation in the standard library.
+/// Library authors should not directly implement this trait, but should prefer
+/// implementing the [`TryFrom`] trait, which offers greater flexibility and
+/// provides an equivalent `TryInto` implementation for free, thanks to a
+/// blanket implementation in the standard library.
 ///
 /// [`TryFrom`]: trait.TryFrom.html
 #[unstable(feature = "try_from", issue = "33417")]
@@ -236,7 +313,8 @@ pub trait TryFrom<T>: Sized {
 
 // As lifts over &
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U>
+{
     fn as_ref(&self) -> &U {
         <T as AsRef<U>>::as_ref(*self)
     }
@@ -244,7 +322,8 @@ fn as_ref(&self) -> &U {
 
 // As lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U>
+{
     fn as_ref(&self) -> &U {
         <T as AsRef<U>>::as_ref(*self)
     }
@@ -260,7 +339,8 @@ fn as_ref(&self) -> &U {
 
 // AsMut lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
+impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U>
+{
     fn as_mut(&mut self) -> &mut U {
         (*self).as_mut()
     }
@@ -276,7 +356,8 @@ fn as_mut(&mut self) -> &mut U {
 
 // From implies Into
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U> Into<U> for T where U: From<T> {
+impl<T, U> Into<U> for T where U: From<T>
+{
     fn into(self) -> U {
         U::from(self)
     }
@@ -291,7 +372,8 @@ fn from(t: T) -> T { t }
 
 // TryFrom implies TryInto
 #[unstable(feature = "try_from", issue = "33417")]
-impl<T, U> TryInto<U> for T where U: TryFrom<T> {
+impl<T, U> TryInto<U> for T where U: TryFrom<T>
+{
     type Error = U::Error;
 
     fn try_into(self) -> Result<U, U::Error> {
@@ -327,7 +409,8 @@ fn as_ref(&self) -> &str {
 
 // FromStr implies TryFrom<&str>
 #[unstable(feature = "try_from", issue = "33417")]
-impl<'a, T> TryFrom<&'a str> for T where T: FromStr {
+impl<'a, T> TryFrom<&'a str> for T where T: FromStr
+{
     type Error = <T as FromStr>::Err;
 
     fn try_from(s: &'a str) -> Result<T, Self::Error> {
index a324a4aed25766da158a71c31bbf098a75462791..4ca303dee43f2ad600237d82680c0a6ddfa6d0f7 100644 (file)
@@ -15,7 +15,6 @@
 // FIXME: #6220 Implement floating point formatting
 
 use fmt;
-use num::Zero;
 use ops::{Div, Rem, Sub};
 use str;
 use slice;
@@ -23,8 +22,9 @@
 use mem;
 
 #[doc(hidden)]
-trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
+trait Int: PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
            Sub<Output=Self> + Copy {
+    fn zero() -> Self;
     fn from_u8(u: u8) -> Self;
     fn to_u8(&self) -> u8;
     fn to_u16(&self) -> u16;
@@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
 
 macro_rules! doit {
     ($($t:ident)*) => ($(impl Int for $t {
+        fn zero() -> $t { 0 }
         fn from_u8(u: u8) -> $t { u as $t }
         fn to_u8(&self) -> u8 { *self as u8 }
         fn to_u16(&self) -> u16 { *self as u16 }
index 3ad91ef15ea7bfa8ba08e3e00398cc8edf1c0cf3..b3f4d75c4da617d61e5d6443ec479016e1ffc466 100644 (file)
@@ -629,8 +629,9 @@ fn enumerate(self) -> Enumerate<Self> where Self: Sized {
     ///
     /// Note that the underlying iterator is still advanced when [`peek`] is
     /// called for the first time: In order to retrieve the next element,
-    /// [`next`] is called on the underlying iterator, hence any side effects of
-    /// the [`next`] method will occur.
+    /// [`next`] is called on the underlying iterator, hence any side effects (i.e.
+    /// anything other than fetching the next value) of the [`next`] method
+    /// will occur.
     ///
     /// [`peek`]: struct.Peekable.html#method.peek
     /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next
index 393c01b0105c5c63d427e042d27bc46592509607..c0aa650a1e854735b6aca0746e14bae1b65bd360 100644 (file)
@@ -16,6 +16,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use cell::UnsafeCell;
 use cmp;
 use hash::Hash;
 use hash::Hasher;
@@ -553,3 +554,19 @@ unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
     #[stable(feature = "rust1", since = "1.0.0")]
     unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
 }
+
+/// Compiler-internal trait used to determine whether a type contains
+/// any `UnsafeCell` internally, but not through an indirection.
+/// This affects, for example, whether a `static` of that type is
+/// placed in read-only static memory or writable static memory.
+#[cfg_attr(not(stage0), lang = "freeze")]
+unsafe trait Freeze {}
+
+unsafe impl Freeze for .. {}
+
+impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
+unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
+unsafe impl<T: ?Sized> Freeze for *const T {}
+unsafe impl<T: ?Sized> Freeze for *mut T {}
+unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
+unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
index 1485c79ead2519ce624c193909bc7559998ca43b..2a60292d0232e1e525606edc20ecc0a9821abc68 100644 (file)
@@ -63,11 +63,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     const NAN: Self;
     const ZERO: Self;
 
-    // suffix of "2" because Float::integer_decode is deprecated
-    #[allow(deprecated)]
-    fn integer_decode2(self) -> (u64, i16, i8) {
-        Float::integer_decode(self)
-    }
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8);
 
     /// Get the raw binary representation of the float.
     fn transmute(self) -> u64;
@@ -160,6 +157,21 @@ impl RawFloat for f32 {
     const ZERO_CUTOFF: i64 = -48;
     other_constants!(f32);
 
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u32 = unsafe { transmute(self) };
+        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0x7fffff) << 1
+        } else {
+            (bits & 0x7fffff) | 0x800000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 127 + 23;
+        (mantissa as u64, exponent, sign)
+    }
+
     fn transmute(self) -> u64 {
         let bits: u32 = unsafe { transmute(self) };
         bits as u64
@@ -171,7 +183,7 @@ fn from_bits(bits: u64) -> f32 {
     }
 
     fn unpack(self) -> Unpacked {
-        let (sig, exp, _sig) = self.integer_decode2();
+        let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
     }
 
@@ -196,6 +208,21 @@ impl RawFloat for f64 {
     const ZERO_CUTOFF: i64 = -326;
     other_constants!(f64);
 
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u64 = unsafe { transmute(self) };
+        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0xfffffffffffff) << 1
+        } else {
+            (bits & 0xfffffffffffff) | 0x10000000000000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 1023 + 52;
+        (mantissa, exponent, sign)
+    }
+
     fn transmute(self) -> u64 {
         let bits: u64 = unsafe { transmute(self) };
         bits
@@ -206,7 +233,7 @@ fn from_bits(bits: u64) -> f64 {
     }
 
     fn unpack(self) -> Unpacked {
-        let (sig, exp, _sig) = self.integer_decode2();
+        let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
     }
 
index 4527d46a27d8a9590f6e64ebdf0376ae561996d6..91ca213e96e0d19b84c38b83668d193790804020 100644 (file)
@@ -143,36 +143,6 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f32 {
-    #[inline]
-    fn nan() -> f32 {
-        NAN
-    }
-
-    #[inline]
-    fn infinity() -> f32 {
-        INFINITY
-    }
-
-    #[inline]
-    fn neg_infinity() -> f32 {
-        NEG_INFINITY
-    }
-
-    #[inline]
-    fn zero() -> f32 {
-        0.0
-    }
-
-    #[inline]
-    fn neg_zero() -> f32 {
-        -0.0
-    }
-
-    #[inline]
-    fn one() -> f32 {
-        1.0
-    }
-
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -214,21 +184,6 @@ fn classify(self) -> Fp {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u32 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0x7fffff) << 1
-        } else {
-            (bits & 0x7fffff) | 0x800000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 127 + 23;
-        (mantissa as u64, exponent, sign)
-    }
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[inline]
index 991a856834948687cf00c59d5879149733af6bc6..7d6d6cef049772f3f2d267a394cf44125015ad69 100644 (file)
@@ -143,36 +143,6 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f64 {
-    #[inline]
-    fn nan() -> f64 {
-        NAN
-    }
-
-    #[inline]
-    fn infinity() -> f64 {
-        INFINITY
-    }
-
-    #[inline]
-    fn neg_infinity() -> f64 {
-        NEG_INFINITY
-    }
-
-    #[inline]
-    fn zero() -> f64 {
-        0.0
-    }
-
-    #[inline]
-    fn neg_zero() -> f64 {
-        -0.0
-    }
-
-    #[inline]
-    fn one() -> f64 {
-        1.0
-    }
-
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -214,21 +184,6 @@ fn classify(self) -> Fp {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u64 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0xfffffffffffff) << 1
-        } else {
-            (bits & 0xfffffffffffff) | 0x10000000000000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 1023 + 52;
-        (mantissa, exponent, sign)
-    }
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[inline]
index 72529d3da01d11b0325827f103096b9b2356c779..b779eefce5752c1bf100488f35106454c83c7770 100644 (file)
@@ -67,7 +67,7 @@ fn min_pos_norm_value() -> Self { f64::MIN_POSITIVE }
 /// Returns a sign (true when negative) and `FullDecoded` value
 /// from given floating point number.
 pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
-    let (mant, exp, sign) = v.integer_decode2();
+    let (mant, exp, sign) = v.integer_decode();
     let even = (mant & 1) == 0;
     let decoded = match v.classify() {
         FpCategory::Nan => FullDecoded::Nan,
@@ -81,7 +81,7 @@ pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
                                           exp: exp, inclusive: even })
         }
         FpCategory::Normal => {
-            let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode2();
+            let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
             if mant == minnorm.0 {
                 // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp)
                 // where maxmant = minnormmant * 2 - 1
index f665cfdee77aeaaaadc9513dda03b45fac286578..5c4a43fbd110a4e4a86202146e8d0ddb05abdde2 100644 (file)
@@ -96,78 +96,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub mod bignum;
 pub mod diy_float;
 
-/// Types that have a "zero" value.
-///
-/// This trait is intended for use in conjunction with `Add`, as an identity:
-/// `x + T::zero() == x`.
-#[unstable(feature = "zero_one",
-           reason = "unsure of placement, wants to use associated constants",
-           issue = "27739")]
-#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \
-                                               Iterator::sum")]
-pub trait Zero: Sized {
-    /// The "zero" (usually, additive identity) for this type.
-    fn zero() -> Self;
-}
-
-/// Types that have a "one" value.
-///
-/// This trait is intended for use in conjunction with `Mul`, as an identity:
-/// `x * T::one() == x`.
-#[unstable(feature = "zero_one",
-           reason = "unsure of placement, wants to use associated constants",
-           issue = "27739")]
-#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \
-                                               Iterator::product")]
-pub trait One: Sized {
-    /// The "one" (usually, multiplicative identity) for this type.
-    fn one() -> Self;
-}
-
-macro_rules! zero_one_impl {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl Zero for $t {
-            #[inline]
-            fn zero() -> Self { 0 }
-        }
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl One for $t {
-            #[inline]
-            fn one() -> Self { 1 }
-        }
-    )*)
-}
-zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
-
-macro_rules! zero_one_impl_float {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl Zero for $t {
-            #[inline]
-            fn zero() -> Self { 0.0 }
-        }
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl One for $t {
-            #[inline]
-            fn one() -> Self { 1.0 }
-        }
-    )*)
-}
-zero_one_impl_float! { f32 f64 }
-
 macro_rules! checked_op {
     ($U:ty, $op:path, $x:expr, $y:expr) => {{
         let (result, overflowed) = unsafe { $op($x as $U, $y as $U) };
@@ -2525,49 +2453,6 @@ pub enum FpCategory {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 pub trait Float: Sized {
-    /// Returns the NaN value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn nan() -> Self;
-    /// Returns the infinite value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn infinity() -> Self;
-    /// Returns the negative infinite value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn neg_infinity() -> Self;
-    /// Returns -0.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn neg_zero() -> Self;
-    /// Returns 0.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn zero() -> Self;
-    /// Returns 1.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn one() -> Self;
-
     /// Returns `true` if this value is NaN and false otherwise.
     #[stable(feature = "core", since = "1.6.0")]
     fn is_nan(self) -> bool;
@@ -2585,14 +2470,6 @@ pub trait Float: Sized {
     #[stable(feature = "core", since = "1.6.0")]
     fn classify(self) -> FpCategory;
 
-    /// Returns the mantissa, exponent and sign as integers, respectively.
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn integer_decode(self) -> (u64, i16, i8);
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[stable(feature = "core", since = "1.6.0")]
index 1a3533317dae68c57aed2528469ed575e738e58d..2b0afc402027f11f1c999846583241f231ed66d0 100644 (file)
@@ -8,23 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::f32;
 use std::f64;
-use std::mem;
 use core::num::diy_float::Fp;
 use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
+use core::num::dec2flt::rawfp::RawFloat;
 
 fn integer_decode(f: f64) -> (u64, i16, i8) {
-    let bits: u64 = unsafe { mem::transmute(f) };
-    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-    let mantissa = if exponent == 0 {
-        (bits & 0xfffffffffffff) << 1
-    } else {
-        (bits & 0xfffffffffffff) | 0x10000000000000
-    };
-    // Exponent bias + mantissa shift
-    exponent -= 1023 + 52;
-    (mantissa, exponent, sign)
+    RawFloat::integer_decode(f)
 }
 
 #[test]
@@ -152,3 +143,35 @@ fn next_float_monotonic() {
     }
     assert!(x > 0.5);
 }
+
+#[test]
+fn test_f32_integer_decode() {
+    assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
+    assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
+    assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
+    assert_eq!(0f32.integer_decode(), (0, -150, 1));
+    assert_eq!((-0f32).integer_decode(), (0, -150, -1));
+    assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
+    assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1));
+
+    // Ignore the "sign" (quiet / signalling flag) of NAN.
+    // It can vary between runtime operations and LLVM folding.
+    let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode();
+    assert_eq!((nan_m, nan_e), (12582912, 105));
+}
+
+#[test]
+fn test_f64_integer_decode() {
+    assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
+    assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
+    assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
+    assert_eq!(0f64.integer_decode(), (0, -1075, 1));
+    assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
+    assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));
+    assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
+
+    // Ignore the "sign" (quiet / signalling flag) of NAN.
+    // It can vary between runtime operations and LLVM folding.
+    let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode();
+    assert_eq!((nan_m, nan_e), (6755399441055744, 972));
+}
index 05a2d197356ef253dfd985166576619ac9b6947f..c34a802d1eb037b44c5252078c7270b5472e0f65 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f
+Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
index fd9750dbfe3f56d9d90ac81b0023149ee7111176..33133f6834b9ab70a32a3e45de54c27929363d35 100644 (file)
@@ -88,15 +88,17 @@ pub enum DepNode<D: Clone + Debug> {
     // predicates for an item wind up in `ItemSignature`).
     AssociatedItems(D),
     ItemSignature(D),
+    IsForeignItem(D),
     TypeParamPredicates((D, D)),
     SizedConstraint(D),
+    DtorckConstraint(D),
     AdtDestructor(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
     TypeckBodiesKrate,
     TypeckTables(D),
     UsedTraitImports(D),
-    MonomorphicConstEval(D),
+    ConstEval(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -171,6 +173,7 @@ macro_rules! check {
             TransCrateItem,
             AssociatedItems,
             ItemSignature,
+            IsForeignItem,
             AssociatedItemDefIds,
             InherentImpls,
             TypeckTables,
@@ -221,16 +224,18 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
             AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
+            IsForeignItem(ref d) => op(d).map(IsForeignItem),
             TypeParamPredicates((ref item, ref param)) => {
                 Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
             }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
+            DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
             AdtDestructor(ref d) => op(d).map(AdtDestructor),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
             UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
-            MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
+            ConstEval(ref d) => op(d).map(ConstEval),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
index 618561f3b02576d92f181535ad0a882d51f7a1a2..30e9f502abc8c83b91c3a91a02f4b5720ef6eb42 100644 (file)
@@ -1829,6 +1829,7 @@ extern "C" fn foo(userdata: Box<i32>) {
     E0314, // closure outlives stack frame
     E0315, // cannot invoke closure outside of its lifetime
     E0316, // nested quantification of lifetimes
+    E0320, // recursive overflow during dropck
     E0473, // dereference of reference outside its lifetime
     E0474, // captured variable `..` does not outlive the enclosing closure
     E0475, // index of slice outside its lifetime
@@ -1847,5 +1848,6 @@ extern "C" fn foo(userdata: Box<i32>) {
     E0489, // type/lifetime parameter not in scope here
     E0490, // a value of type `..` is borrowed for too long
     E0495, // cannot infer an appropriate lifetime due to conflicting requirements
-    E0566  // conflicting representation hints
+    E0566, // conflicting representation hints
+    E0587, // conflicting packed and align representation hints
 }
index 54ae947214091653c329807a603495f7992ea099..bf292ccb8d86d064212c1d33c40e56b90c0c144a 100644 (file)
@@ -57,6 +57,9 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
         };
 
         let mut conflicting_reprs = 0;
+        let mut found_packed = false;
+        let mut found_align = false;
+
         for word in words {
 
             let name = match word.name() {
@@ -84,6 +87,7 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
                                 ("attribute should be applied to struct or union",
                                  "a struct or union")
                     } else {
+                        found_packed = true;
                         continue
                     }
                 }
@@ -96,6 +100,15 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
                         continue
                     }
                 }
+                "align" => {
+                    found_align = true;
+                    if target != Target::Struct {
+                        ("attribute should be applied to struct",
+                         "a struct")
+                    } else {
+                        continue
+                    }
+                }
                 "i8" | "u8" | "i16" | "u16" |
                 "i32" | "u32" | "i64" | "u64" |
                 "isize" | "usize" => {
@@ -117,6 +130,10 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
             span_warn!(self.sess, attr.span, E0566,
                        "conflicting representation hints");
         }
+        if found_align && found_packed {
+            struct_span_err!(self.sess, attr.span, E0587,
+                             "conflicting packed and align representation hints").emit();
+        }
     }
 
     fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
index f55462fb5deb636925504c6105ac71869b434d89..16af98c2035480ef382ab55f7dbed9a5b521fb9a 100644 (file)
@@ -273,6 +273,12 @@ fn hash_stable<W: StableHasherResult>(&self,
             ConstVal::Bool(value) => {
                 value.hash_stable(hcx, hasher);
             }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Variant(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
             ConstVal::Function(def_id, substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
@@ -296,9 +302,6 @@ fn hash_stable<W: StableHasherResult>(&self,
                 value.hash_stable(hcx, hasher);
                 times.hash_stable(hcx, hasher);
             }
-            ConstVal::Char(value) => {
-                value.hash_stable(hcx, hasher);
-            }
         }
     }
 }
index 697a1ecadc456afe92b6702999aa1d8851aa3cd9..922842136dc9f398464b422bd2437400e13de105 100644 (file)
@@ -99,7 +99,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
             ty::ReEmpty |
             ty::ReErased => {
                 // replace all free regions with 'erased
-                self.tcx().mk_region(ty::ReErased)
+                self.tcx().types.re_erased
             }
         }
     }
index 0bb9e2c7fa15c91345ea6c7ec0c7acb630d91410..fa6775737b57df93f167f176f2d8c8dd6bc0e4ac 100644 (file)
@@ -948,7 +948,7 @@ fn lub_concrete_regions(&self,
                 } else {
                     // otherwise, we don't know what the free region is,
                     // so we must conservatively say the LUB is static:
-                    self.tcx.mk_region(ReStatic)
+                    self.tcx.types.re_static
                 }
             }
 
@@ -971,7 +971,7 @@ fn lub_concrete_regions(&self,
                 if a == b {
                     a
                 } else {
-                    self.tcx.mk_region(ReStatic)
+                    self.tcx.types.re_static
                 }
             }
         }
@@ -1018,7 +1018,7 @@ fn infer_variable_values(&self,
 
     fn construct_var_data(&self) -> Vec<VarValue<'tcx>> {
         (0..self.num_vars() as usize)
-            .map(|_| Value(self.tcx.mk_region(ty::ReEmpty)))
+            .map(|_| Value(self.tcx.types.re_empty))
             .collect()
     }
 
@@ -1493,7 +1493,7 @@ fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                           -> &'tcx ty::Region {
     match values[rid.index as usize] {
         Value(r) => r,
-        ErrorValue => tcx.mk_region(ReStatic), // Previously reported error.
+        ErrorValue => tcx.types.re_static, // Previously reported error.
     }
 }
 
index b4c5af9401944102f6b9b613b05e01b0259fb0c9..ec7b3c4dd8dffd4514205789364611c8a89a4a26 100644 (file)
@@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> {
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
+    Char(char),
+    Variant(DefId),
     Function(DefId, &'tcx Substs<'tcx>),
     Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
     Tuple(Vec<ConstVal<'tcx>>),
     Array(Vec<ConstVal<'tcx>>),
     Repeat(Box<ConstVal<'tcx>>, u64),
-    Char(char),
 }
 
 impl<'tcx> ConstVal<'tcx> {
@@ -54,12 +55,13 @@ pub fn description(&self) -> &'static str {
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
+            Char(..) => "char",
+            Variant(_) => "enum variant",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
             Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
-            Char(..) => "char",
         }
     }
 
@@ -85,7 +87,6 @@ pub enum ErrKind<'tcx> {
     MissingStructField,
     NegateOn(ConstVal<'tcx>),
     NotOn(ConstVal<'tcx>),
-    CallOn(ConstVal<'tcx>),
 
     NonConstPath,
     UnimplementedConstVal(&'static str),
@@ -145,7 +146,6 @@ macro_rules! simple {
             CannotCast => simple!("can't cast this type"),
             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
-            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
 
             MissingStructField  => simple!("nonexistent struct field"),
             NonConstPath        => simple!("non-constant path in constant expression"),
@@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt,
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
-    match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) {
+    let substs = Substs::empty();
+    match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
index cbbfeacadb4087a2e8912bb415986d57435ec605..3251addcb3283310ffaf7b32dcca5f5019c58d95 100644 (file)
@@ -188,14 +188,13 @@ pub trait CrateStore {
     fn visibility(&self, def: DefId) -> ty::Visibility;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>;
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
 
     // trait info
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
@@ -250,8 +249,8 @@ fn retrace_path(&self,
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body>;
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body;
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
     fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
@@ -323,14 +322,13 @@ fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>> {
     }
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics
         { bug!("item_generics_cloned") }
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") }
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
 
     // trait info
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
 
     // impl info
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
@@ -401,9 +399,9 @@ fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children")
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body> {
-        bug!("maybe_get_item_body")
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body {
+        bug!("item_body")
     }
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
         bug!("item_body_nested_bodies")
index a10f52e2d4cc06457553dbb5d59a2a15f7dad5bc..8b26315915826ce41723cc3f27afd06c183aa900 100644 (file)
@@ -426,7 +426,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
 
             hir::ExprMatch(ref discr, ref arms, _) => {
                 let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
-                let r = self.tcx().mk_region(ty::ReEmpty);
+                let r = self.tcx().types.re_empty;
                 self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant);
 
                 // treatment of the discriminant is handled while walking the arms.
index 5989fa9007c4446ee177acd71be6de9ed68de0db..3b506d748ef7a01ff17f88dcd524da8f22cc0100 100644 (file)
@@ -223,9 +223,10 @@ pub fn collect(&mut self, krate: &hir::Crate) {
 
 pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
     for attribute in attrs {
-        match attribute.value_str() {
-            Some(value) if attribute.check_name("lang") => return Some(value),
-            _ => {}
+        if attribute.check_name("lang") {
+            if let Some(value) = attribute.value_str() {
+                return Some(value)
+            }
         }
     }
 
@@ -274,6 +275,7 @@ pub fn collect_language_items(session: &Session,
     UnsizeTraitLangItem,             "unsize",                  unsize_trait;
     CopyTraitLangItem,               "copy",                    copy_trait;
     SyncTraitLangItem,               "sync",                    sync_trait;
+    FreezeTraitLangItem,             "freeze",                  freeze_trait;
 
     DropTraitLangItem,               "drop",                    drop_trait;
 
index 7d3c17a048917adf85f0477eae8ce3e0bf29d801..188fcc9141492447de66d14cf6486ef4f5ea7136 100644 (file)
@@ -871,8 +871,8 @@ pub fn cat_rvalue_node(&self,
         // we can promote to a constant, otherwise equal to enclosing temp
         // lifetime.
         let (re, old_re) = if promotable {
-            (self.tcx().mk_region(ty::ReStatic),
-             self.tcx().mk_region(ty::ReStatic))
+            (self.tcx().types.re_static,
+             self.tcx().types.re_static)
         } else {
             self.temporary_scope(id)
         };
index 63455f94cedff32370213bbaf6f1e200fc8db518..be4ec16cd63aab3038176482046aa024893b9564 100644 (file)
@@ -18,6 +18,7 @@
 use hir::map as hir_map;
 use hir::def::Def;
 use hir::def_id::{DefId, CrateNum};
+use std::rc::Rc;
 use ty::{self, TyCtxt};
 use ty::maps::Providers;
 use middle::privacy;
@@ -362,11 +363,11 @@ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
 
-pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
+pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<NodeSet> {
     ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE)
 }
 
-fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet {
+fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc<NodeSet> {
     debug_assert!(crate_num == LOCAL_CRATE);
 
     let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE);
@@ -411,7 +412,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) ->
     reachable_context.propagate();
 
     // Return the set of reachable symbols.
-    reachable_context.reachable_symbols
+    Rc::new(reachable_context.reachable_symbols)
 }
 
 pub fn provide(providers: &mut Providers) {
index 9ff64b295b765ee8a5f67026f15312c2938cadc0..bfb72b5df7b2e7143d9dc058490c12f2444f375b 100644 (file)
@@ -1307,10 +1307,11 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
+        Char(c) => write!(fmt, "{:?}", c),
+        Variant(def_id) |
         Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
-        Char(c) => write!(fmt, "{:?}", c),
     }
 }
 
index d49affa3e872c0172b7d245a6129ee5de377611c..908bb337fa18e1b3b9cd57bac62262e675204b7c 100644 (file)
@@ -443,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                         // Otherwise, we have something of the form
                         // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
                         Some(t_a) => {
-                            let r_static = selcx.tcx().mk_region(ty::ReStatic);
+                            let r_static = selcx.tcx().types.re_static;
                             register_region_obligation(t_a, r_static,
                                                        obligation.cause.clone(),
                                                        region_obligations);
index 0ff379b30ffd0c3ff8474a159b17d56ccba7d0df..281c1e253798cd080383731626b90d98cfb0d6cc 100644 (file)
@@ -55,6 +55,7 @@
 mod select;
 mod specialize;
 mod structural_impls;
+pub mod trans;
 mod util;
 
 /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
@@ -628,7 +629,7 @@ pub fn get_vtable_methods<'a, 'tcx>(
             // the method may have some early-bound lifetimes, add
             // regions for those
             let substs = Substs::for_item(tcx, def_id,
-                                          |_, _| tcx.mk_region(ty::ReErased),
+                                          |_, _| tcx.types.re_erased,
                                           |def, _| trait_ref.substs().type_for_def(def));
 
             // the trait type may have higher-ranked lifetimes in it;
index d190635bec3063ce3c0e8193fba6cde6942e0800..e53932888022b311264b69d5d1abde6fd3678781 100644 (file)
@@ -37,6 +37,9 @@ pub enum ObjectSafetyViolation {
 
     /// Method has something illegal
     Method(ast::Name, MethodViolationCode),
+
+    /// Associated const
+    AssociatedConst(ast::Name),
 }
 
 impl ObjectSafetyViolation {
@@ -54,6 +57,8 @@ pub fn error_msg(&self) -> Cow<'static, str> {
                          in its arguments or return type", name).into(),
             ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
                 format!("method `{}` has generic type parameters", name).into(),
+            ObjectSafetyViolation::AssociatedConst(name) =>
+                format!("the trait cannot contain associated consts like `{}`", name).into(),
         }
     }
 }
@@ -141,6 +146,10 @@ fn object_safety_violations_for_trait(self, trait_def_id: DefId)
             violations.push(ObjectSafetyViolation::SupertraitSelf);
         }
 
+        violations.extend(self.associated_items(trait_def_id)
+            .filter(|item| item.kind == ty::AssociatedKind::Const)
+            .map(|item| ObjectSafetyViolation::AssociatedConst(item.name)));
+
         debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
                trait_def_id,
                violations);
index 70ddcff5181bedf04dd3b07daed92d9b25ef87a8..207016170faa20655d5b564fa0fbcdc66c03a4b9 100644 (file)
@@ -943,17 +943,17 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
                     debug!("Retaining candidate #{}/{}: {:?}",
                            i, candidates.len(), candidates[i]);
                     i += 1;
+
+                    // If there are *STILL* multiple candidates, give up
+                    // and report ambiguity.
+                    if i > 1 {
+                        debug!("multiple matches, ambig");
+                        return Ok(None);
+                    }
                 }
             }
         }
 
-        // If there are *STILL* multiple candidates, give up and
-        // report ambiguity.
-        if candidates.len() > 1 {
-            debug!("multiple matches, ambig");
-            return Ok(None);
-        }
-
         // If there are *NO* candidates, then there are no impls --
         // that we know of, anyway. Note that in the case where there
         // are unbound type variables within the obligation, it might
@@ -1300,8 +1300,13 @@ fn assemble_candidates_from_caller_bounds<'o>(&mut self,
                             .iter()
                             .filter_map(|o| o.to_opt_poly_trait_ref());
 
+        // micro-optimization: filter out predicates relating to different
+        // traits.
+        let matching_bounds =
+            all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+
         let matching_bounds =
-            all_bounds.filter(
+            matching_bounds.filter(
                 |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
 
         let param_candidates =
@@ -1790,11 +1795,9 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyAdt(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
-                Where(ty::Binder(match sized_crit.sty {
-                    ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
-                    ty::TyBool => vec![],
-                    _ => vec![sized_crit.subst(self.tcx(), substs)]
-                }))
+                Where(ty::Binder(
+                    sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
+                ))
             }
 
             ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
new file mode 100644 (file)
index 0000000..e38306a
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2012-2014 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 file contains various trait resolution methods used by trans.
+// They all assume regions can be erased and monomorphic types.  It
+// seems likely that they should eventually be merged into more
+// general routines.
+
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::DefId;
+use infer::TransNormalize;
+use std::cell::RefCell;
+use std::marker::PhantomData;
+use syntax::ast;
+use syntax_pos::Span;
+use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable};
+use ty::{self, Ty, TyCtxt};
+use ty::subst::{Subst, Substs};
+use ty::fold::{TypeFoldable, TypeFolder};
+use util::common::MemoizationMap;
+
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Attempts to resolve an obligation to a vtable.. The result is
+    /// a shallow vtable resolution -- meaning that we do not
+    /// (necessarily) resolve all nested obligations on the impl. Note
+    /// that type check should guarantee to us that all nested
+    /// obligations *could be* resolved if we wanted to.
+    pub fn trans_fulfill_obligation(self,
+                                    span: Span,
+                                    trait_ref: ty::PolyTraitRef<'tcx>)
+                                    -> Vtable<'tcx, ()>
+    {
+        // Remove any references to regions; this helps improve caching.
+        let trait_ref = self.erase_regions(&trait_ref);
+
+        self.trans_trait_caches.trait_cache.memoize(trait_ref, || {
+            debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
+                   trait_ref, trait_ref.def_id());
+
+            // Do the initial selection for the obligation. This yields the
+            // shallow result we are looking for -- that is, what specific impl.
+            self.infer_ctxt((), Reveal::All).enter(|infcx| {
+                let mut selcx = SelectionContext::new(&infcx);
+
+                let obligation_cause = ObligationCause::misc(span,
+                                                             ast::DUMMY_NODE_ID);
+                let obligation = Obligation::new(obligation_cause,
+                                                 trait_ref.to_poly_trait_predicate());
+
+                let selection = match selcx.select(&obligation) {
+                    Ok(Some(selection)) => selection,
+                    Ok(None) => {
+                        // Ambiguity can happen when monomorphizing during trans
+                        // expands to some humongo type that never occurred
+                        // statically -- this humongo type can then overflow,
+                        // leading to an ambiguous result. So report this as an
+                        // overflow bug, since I believe this is the only case
+                        // where ambiguity can result.
+                        debug!("Encountered ambiguity selecting `{:?}` during trans, \
+                                presuming due to overflow",
+                               trait_ref);
+                        self.sess.span_fatal(span,
+                                            "reached the recursion limit during monomorphization \
+                                             (selection ambiguity)");
+                    }
+                    Err(e) => {
+                        span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
+                                  e, trait_ref)
+                    }
+                };
+
+                debug!("fulfill_obligation: selection={:?}", selection);
+
+                // Currently, we use a fulfillment context to completely resolve
+                // all nested obligations. This is because they can inform the
+                // inference of the impl's type parameters.
+                let mut fulfill_cx = FulfillmentContext::new();
+                let vtable = selection.map(|predicate| {
+                    debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
+                    fulfill_cx.register_predicate_obligation(&infcx, predicate);
+                });
+                let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
+
+                info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
+                vtable
+            })
+        })
+    }
+
+    /// Monomorphizes a type from the AST by first applying the in-scope
+    /// substitutions and then normalizing any associated types.
+    pub fn trans_apply_param_substs<T>(self,
+                                       param_substs: &Substs<'tcx>,
+                                       value: &T)
+                                       -> T
+        where T: TransNormalize<'tcx>
+    {
+        debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
+        let substituted = value.subst(self, param_substs);
+        let substituted = self.erase_regions(&substituted);
+        AssociatedTypeNormalizer::new(self).fold(&substituted)
+    }
+}
+
+struct AssociatedTypeNormalizer<'a, 'gcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'gcx>,
+}
+
+impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
+    fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self {
+        AssociatedTypeNormalizer { tcx }
+    }
+
+    fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
+        if !value.has_projection_types() {
+            value.clone()
+        } else {
+            value.fold_with(self)
+        }
+    }
+}
+
+impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
+    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
+        if !ty.has_projection_types() {
+            ty
+        } else {
+            self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
+                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
+                self.tcx.normalize_associated_type(&ty)
+            })
+        }
+    }
+}
+
+/// Specializes caches used in trans -- in particular, they assume all
+/// types are fully monomorphized and that free regions can be erased.
+pub struct TransTraitCaches<'tcx> {
+    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
+    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
+}
+
+impl<'tcx> TransTraitCaches<'tcx> {
+    pub fn new(graph: DepGraph) -> Self {
+        TransTraitCaches {
+            trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
+            project_cache: RefCell::new(DepTrackingMap::new(graph)),
+        }
+    }
+}
+
+// Implement DepTrackingMapConfig for `trait_cache`
+pub struct TraitSelectionCache<'tcx> {
+    data: PhantomData<&'tcx ()>
+}
+
+impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
+    type Key = ty::PolyTraitRef<'tcx>;
+    type Value = Vtable<'tcx, ()>;
+    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
+        key.to_poly_trait_predicate().dep_node()
+    }
+}
+
+// # Global Cache
+
+pub struct ProjectionCache<'gcx> {
+    data: PhantomData<&'gcx ()>
+}
+
+impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
+    type Key = Ty<'gcx>;
+    type Value = Ty<'gcx>;
+    fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
+        // Ideally, we'd just put `key` into the dep-node, but we
+        // can't put full types in there. So just collect up all the
+        // def-ids of structs/enums as well as any traits that we
+        // project out of. It doesn't matter so much what we do here,
+        // except that if we are too coarse, we'll create overly
+        // coarse edges between impls and the trans. For example, if
+        // we just used the def-id of things we are projecting out of,
+        // then the key for `<Foo as SomeTrait>::T` and `<Bar as
+        // SomeTrait>::T` would both share a dep-node
+        // (`TraitSelect(SomeTrait)`), and hence the impls for both
+        // `Foo` and `Bar` would be considered inputs. So a change to
+        // `Bar` would affect things that just normalized `Foo`.
+        // Anyway, this heuristic is not ideal, but better than
+        // nothing.
+        let def_ids: Vec<DefId> =
+            key.walk()
+               .filter_map(|t| match t.sty {
+                   ty::TyAdt(adt_def, _) => Some(adt_def.did),
+                   ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
+                   _ => None,
+               })
+               .collect();
+
+        DepNode::ProjectionCache { def_ids: def_ids }
+    }
+}
+
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
deleted file mode 100644 (file)
index e142959..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use hir::def_id::{DefId};
-use ty::{self, Ty, TyCtxt};
-use util::common::MemoizationMap;
-use util::nodemap::FxHashMap;
-
-use std::fmt;
-use std::ops;
-
-use syntax::ast;
-
-/// Type contents is how the type checker reasons about kinds.
-/// They track what kinds of things are found within a type.  You can
-/// think of them as kind of an "anti-kind".  They track the kinds of values
-/// and thinks that are contained in types.  Having a larger contents for
-/// a type tends to rule that type *out* from various kinds.  For example,
-/// a type that contains a reference is not sendable.
-///
-/// The reason we compute type contents and not kinds is that it is
-/// easier for me (nmatsakis) to think about what is contained within
-/// a type than to think about what is *not* contained within a type.
-#[derive(Clone, Copy)]
-pub struct TypeContents {
-    pub bits: u64
-}
-
-macro_rules! def_type_content_sets {
-    (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
-        #[allow(non_snake_case)]
-        mod $mname {
-            use super::TypeContents;
-            $(
-                #[allow(non_upper_case_globals)]
-                pub const $name: TypeContents = TypeContents { bits: $bits };
-             )+
-        }
-    }
-}
-
-def_type_content_sets! {
-    mod TC {
-        None                                = 0b0000_0000__0000_0000__0000,
-
-        // Things that are interior to the value (first nibble):
-        InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
-        InteriorParam                       = 0b0000_0000__0000_0000__0100,
-        // InteriorAll                         = 0b00000000__00000000__1111,
-
-        // Things that are owned by the value (second and third nibbles):
-        OwnsDtor                            = 0b0000_0000__0000_0010__0000,
-        // OwnsAll                             = 0b0000_0000__1111_1111__0000,
-
-        // All bits
-        All                                 = 0b1111_1111__1111_1111__1111
-    }
-}
-
-impl TypeContents {
-    pub fn when(&self, cond: bool) -> TypeContents {
-        if cond {*self} else {TC::None}
-    }
-
-    pub fn intersects(&self, tc: TypeContents) -> bool {
-        (self.bits & tc.bits) != 0
-    }
-
-    pub fn interior_param(&self) -> bool {
-        self.intersects(TC::InteriorParam)
-    }
-
-    pub fn interior_unsafe(&self) -> bool {
-        self.intersects(TC::InteriorUnsafe)
-    }
-
-    pub fn needs_drop(&self, _: TyCtxt) -> bool {
-        self.intersects(TC::OwnsDtor)
-    }
-
-    pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
-        I: IntoIterator<Item=T>,
-        F: FnMut(T) -> TypeContents,
-    {
-        v.into_iter().fold(TC::None, |tc, ty| tc | f(ty))
-    }
-}
-
-impl ops::BitOr for TypeContents {
-    type Output = TypeContents;
-
-    fn bitor(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits | other.bits}
-    }
-}
-
-impl ops::BitAnd for TypeContents {
-    type Output = TypeContents;
-
-    fn bitand(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & other.bits}
-    }
-}
-
-impl ops::Sub for TypeContents {
-    type Output = TypeContents;
-
-    fn sub(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & !other.bits}
-    }
-}
-
-impl fmt::Debug for TypeContents {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeContents({:b})", self.bits)
-    }
-}
-
-impl<'a, 'tcx> ty::TyS<'tcx> {
-    pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents {
-        return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap()));
-
-        fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           ty: Ty<'tcx>,
-                           cache: &mut FxHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
-        {
-            // Subtle: Note that we are *not* using tcx.tc_cache here but rather a
-            // private cache for this walk.  This is needed in the case of cyclic
-            // types like:
-            //
-            //     struct List { next: Box<Option<List>>, ... }
-            //
-            // When computing the type contents of such a type, we wind up deeply
-            // recursing as we go.  So when we encounter the recursive reference
-            // to List, we temporarily use TC::None as its contents.  Later we'll
-            // patch up the cache with the correct value, once we've computed it
-            // (this is basically a co-inductive process, if that helps).  So in
-            // the end we'll compute TC::OwnsOwned, in this case.
-            //
-            // The problem is, as we are doing the computation, we will also
-            // compute an *intermediate* contents for, e.g., Option<List> of
-            // TC::None.  This is ok during the computation of List itself, but if
-            // we stored this intermediate value into tcx.tc_cache, then later
-            // requests for the contents of Option<List> would also yield TC::None
-            // which is incorrect.  This value was computed based on the crutch
-            // value for the type contents of list.  The correct value is
-            // TC::OwnsOwned.  This manifested as issue #4821.
-            if let Some(tc) = cache.get(&ty) {
-                return *tc;
-            }
-            // Must check both caches!
-            if let Some(tc) = tcx.tc_cache.borrow().get(&ty) {
-                return *tc;
-            }
-            cache.insert(ty, TC::None);
-
-            let result = match ty.sty {
-                // usize and isize are ffi-unsafe
-                ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => {
-                    TC::None
-                }
-
-                // Scalar and unique types are sendable, and durable
-                ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
-                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
-                ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
-                    TC::None
-                }
-
-                ty::TyDynamic(..) => {
-                    TC::All - TC::InteriorParam
-                }
-
-                ty::TyRawPtr(_) => {
-                    TC::None
-                }
-
-                ty::TyRef(..) => {
-                    TC::None
-                }
-
-                ty::TyArray(ty, _) => {
-                    tc_ty(tcx, ty, cache)
-                }
-
-                ty::TySlice(ty) => {
-                    tc_ty(tcx, ty, cache)
-                }
-                ty::TyStr => TC::None,
-
-                ty::TyClosure(def_id, ref substs) => {
-                    TypeContents::union(
-                        substs.upvar_tys(def_id, tcx),
-                        |ty| tc_ty(tcx, &ty, cache))
-                }
-
-                ty::TyTuple(ref tys, _) => {
-                    TypeContents::union(&tys[..],
-                                        |ty| tc_ty(tcx, *ty, cache))
-                }
-
-                ty::TyAdt(def, substs) => {
-                    let mut res =
-                        TypeContents::union(&def.variants, |v| {
-                            TypeContents::union(&v.fields, |f| {
-                                tc_ty(tcx, f.ty(tcx, substs), cache)
-                            })
-                        });
-
-                    if def.is_union() {
-                        // unions don't have destructors regardless of the child types
-                        res = res - TC::OwnsDtor;
-                    }
-
-                    if def.has_dtor(tcx) {
-                        res = res | TC::OwnsDtor;
-                    }
-
-                    apply_lang_items(tcx, def.did, res)
-                }
-
-                ty::TyProjection(..) |
-                ty::TyParam(_) |
-                ty::TyAnon(..) => {
-                    TC::All
-                }
-
-                ty::TyInfer(_) |
-                ty::TyError => {
-                    bug!("asked to compute contents of error type");
-                }
-            };
-
-            cache.insert(ty, result);
-            result
-        }
-
-        fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                      did: DefId, tc: TypeContents)
-                                      -> TypeContents {
-            if Some(did) == tcx.lang_items.unsafe_cell_type() {
-                tc | TC::InteriorUnsafe
-            } else {
-                tc
-            }
-        }
-    }
-}
index 8b7438c0bfad2ed5f73efbfece42ffbbd22978d4..b20ac8ddbfc8a925bd85ea1c0dcff79facae0486 100644 (file)
@@ -190,6 +190,10 @@ pub struct CommonTypes<'tcx> {
     pub f64: Ty<'tcx>,
     pub never: Ty<'tcx>,
     pub err: Ty<'tcx>,
+
+    pub re_empty: &'tcx Region,
+    pub re_static: &'tcx Region,
+    pub re_erased: &'tcx Region,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -360,6 +364,14 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'t
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         let mk = |sty| interners.intern_ty(sty, None);
+        let mk_region = |r| {
+            if let Some(r) = interners.region.borrow().get(&r) {
+                return r.0;
+            }
+            let r = interners.arena.alloc(r);
+            interners.region.borrow_mut().insert(Interned(r));
+            &*r
+        };
         CommonTypes {
             bool: mk(TyBool),
             char: mk(TyChar),
@@ -379,6 +391,10 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
             u128: mk(TyUint(ast::UintTy::U128)),
             f32: mk(TyFloat(ast::FloatTy::F32)),
             f64: mk(TyFloat(ast::FloatTy::F64)),
+
+            re_empty: mk_region(Region::ReEmpty),
+            re_static: mk_region(Region::ReStatic),
+            re_erased: mk_region(Region::ReErased),
         }
     }
 }
@@ -407,6 +423,8 @@ pub struct GlobalCtxt<'tcx> {
 
     pub specializes_cache: RefCell<traits::SpecializesCache>,
 
+    pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
+
     pub dep_graph: DepGraph,
 
     /// Common types, pre-interned for your convenience.
@@ -436,9 +454,6 @@ pub struct GlobalCtxt<'tcx> {
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
 
-    // Cache for the type-contents routine. FIXME -- track deps?
-    pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
-
     // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
@@ -692,6 +707,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
         providers[LOCAL_CRATE] = local_providers;
         tls::enter_global(GlobalCtxt {
             sess: s,
+            trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
             specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_arenas: arenas,
             global_interners: interners,
@@ -708,7 +724,6 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             freevars: RefCell::new(resolutions.freevars),
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
             rcache: RefCell::new(FxHashMap()),
-            tc_cache: RefCell::new(FxHashMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
@@ -1233,7 +1248,7 @@ pub fn mk_str(self) -> Ty<'tcx> {
     }
 
     pub fn mk_static_str(self) -> Ty<'tcx> {
-        self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
+        self.mk_imm_ref(self.types.re_static, self.mk_str())
     }
 
     pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
index e29653c9e88a03a7b81042850a40e41dd7886c45..969d040e7a6e8f94e92fdd724be49dbce6769907 100644 (file)
@@ -410,7 +410,7 @@ fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool
     pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0
+        self.replace_late_bound_regions(value, |_| self.types.re_erased).0
     }
 
     /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
@@ -538,7 +538,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
                 // whenever a substitution occurs.
                 match *r {
                     ty::ReLateBound(..) => r,
-                    _ => self.tcx().mk_region(ty::ReErased)
+                    _ => self.tcx().types.re_erased
                 }
             }
         }
@@ -565,6 +565,22 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
     }
 }
 
+pub fn shift_region_ref<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    region: &'tcx ty::Region,
+    amount: u32)
+    -> &'tcx ty::Region
+{
+    match region {
+        &ty::ReLateBound(debruijn, br) if amount > 0 => {
+            tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br))
+        }
+        _ => {
+            region
+        }
+    }
+}
+
 pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                         amount: u32, value: &T) -> T
     where T: TypeFoldable<'tcx>
@@ -573,7 +589,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
            value, amount);
 
     value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
-        tcx.mk_region(shift_region(*region, amount))
+        shift_region_ref(tcx, region, amount)
     }))
 }
 
index 67287f1b4ff72bf0ae9618f4c0deb014e1a26b05..cfff3d0e573603340808c3e73b98db8e8e30b3e4 100644 (file)
 use ty::{self, Ty, TypeFoldable, Substs};
 use util::ppaux;
 
-use std::borrow::Cow;
 use std::fmt;
-use syntax::ast;
-
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Instance<'tcx> {
@@ -59,7 +56,7 @@ pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> {
+    pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
         tcx.get_attrs(self.def_id())
     }
 
index df60eee8c02431d761e1a11e762b2c5081c46a73..49cc4e7c993a53de08f46a0c11feab317722c3ec 100644 (file)
@@ -548,8 +548,12 @@ pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
 /// A structure, a product type in ADT terms.
 #[derive(PartialEq, Eq, Hash, Debug)]
 pub struct Struct {
+    /// Maximum alignment of fields and repr alignment.
     pub align: Align,
 
+    /// Primitive alignment of fields without repr alignment.
+    pub primitive_align: Align,
+
     /// If true, no alignment padding is used.
     pub packed: bool,
 
@@ -583,10 +587,20 @@ impl<'a, 'gcx, 'tcx> Struct {
     fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
                   repr: &ReprOptions, kind: StructKind,
                   scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
-        let packed = repr.packed();
+        if repr.packed() && repr.align > 0 {
+            bug!("Struct cannot be packed and aligned");
+        }
+
+        let align = if repr.packed() {
+            dl.i8_align
+        } else {
+            dl.aggregate_align
+        };
+
         let mut ret = Struct {
-            align: if packed { dl.i8_align } else { dl.aggregate_align },
-            packed: packed,
+            align: align,
+            primitive_align: align,
+            packed: repr.packed(),
             sized: true,
             offsets: vec![],
             memory_index: vec![],
@@ -660,7 +674,9 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
             // Invariant: offset < dl.obj_size_bound() <= 1<<61
             if !ret.packed {
                 let align = field.align(dl);
+                let primitive_align = field.primitive_align(dl);
                 ret.align = ret.align.max(align);
+                ret.primitive_align = ret.primitive_align.max(primitive_align);
                 offset = offset.abi_align(align);
             }
 
@@ -671,6 +687,11 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
                            .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
         }
 
+        if repr.align > 0 {
+            let repr_align = repr.align as u64;
+            ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap());
+            debug!("Struct::new repr_align: {:?}", repr_align);
+        }
 
         debug!("Struct::new min_size: {:?}", offset);
         ret.min_size = offset;
@@ -801,7 +822,7 @@ fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     return Ok(None);
                 }
@@ -836,12 +857,23 @@ fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
         Ok(None)
     }
+
+    pub fn over_align(&self) -> Option<u32> {
+        let align = self.align.abi();
+        let primitive_align = self.primitive_align.abi();
+        if align > primitive_align {
+            Some(align as u32)
+        } else {
+            None
+        }
+    }
 }
 
 /// An untagged union.
 #[derive(PartialEq, Eq, Hash, Debug)]
 pub struct Union {
     pub align: Align,
+    pub primitive_align: Align,
 
     pub min_size: Size,
 
@@ -851,8 +883,10 @@ pub struct Union {
 
 impl<'a, 'gcx, 'tcx> Union {
     fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+        let align = if packed { dl.i8_align } else { dl.aggregate_align };
         Union {
-            align: if packed { dl.i8_align } else { dl.aggregate_align },
+            align: align,
+            primitive_align: align,
             min_size: Size::from_bytes(0),
             packed: packed,
         }
@@ -875,6 +909,7 @@ fn extend<I>(&mut self, dl: &TargetDataLayout,
 
             if !self.packed {
                 self.align = self.align.max(field.align(dl));
+                self.primitive_align = self.primitive_align.max(field.primitive_align(dl));
             }
             self.min_size = cmp::max(self.min_size, field.size(dl));
         }
@@ -888,6 +923,16 @@ fn extend<I>(&mut self, dl: &TargetDataLayout,
     pub fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
+
+    pub fn over_align(&self) -> Option<u32> {
+        let align = self.align.abi();
+        let primitive_align = self.primitive_align.abi();
+        if align > primitive_align {
+            Some(align as u32)
+        } else {
+            None
+        }
+    }
 }
 
 /// The first half of a fat pointer.
@@ -924,6 +969,7 @@ pub enum Layout {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
         align: Align,
+        primitive_align: Align,
         element_size: Size,
         count: u64
     },
@@ -970,7 +1016,8 @@ pub enum Layout {
         discr: Integer,
         variants: Vec<Struct>,
         size: Size,
-        align: Align
+        align: Align,
+        primitive_align: Align,
     },
 
     /// Two cases distinguished by a nullable pointer: the case with discriminant
@@ -1020,28 +1067,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// Helper function for normalizing associated types in an inference context.
-fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                             ty: Ty<'gcx>)
-                                             -> Ty<'gcx> {
-    if !ty.has_projection_types() {
-        return ty;
-    }
-
-    let mut selcx = traits::SelectionContext::new(infcx);
-    let cause = traits::ObligationCause::dummy();
-    let traits::Normalized { value: result, obligations } =
-        traits::normalize(&mut selcx, cause, &ty);
-
-    let mut fulfill_cx = traits::FulfillmentContext::new();
-
-    for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(infcx, obligation);
-    }
-
-    infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
-}
-
 impl<'a, 'gcx, 'tcx> Layout {
     pub fn compute_uncached(ty: Ty<'gcx>,
                             infcx: &InferCtxt<'a, 'gcx, 'tcx>)
@@ -1053,7 +1078,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
 
         let ptr_layout = |pointee: Ty<'gcx>| {
             let non_zero = !ty.is_unsafe_ptr();
-            let pointee = normalize_associated_type(infcx, pointee);
+            let pointee = infcx.normalize_projections(pointee);
             if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
                 Ok(Scalar { value: Pointer, non_zero: non_zero })
             } else {
@@ -1118,6 +1143,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 Array {
                     sized: true,
                     align: element.align(dl),
+                    primitive_align: element.primitive_align(dl),
                     element_size: element_size,
                     count: count
                 }
@@ -1127,6 +1153,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 Array {
                     sized: false,
                     align: element.align(dl),
+                    primitive_align: element.primitive_align(dl),
                     element_size: element.size(dl),
                     count: 0
                 }
@@ -1135,6 +1162,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 Array {
                     sized: false,
                     align: dl.i8_align,
+                    primitive_align: dl.i8_align,
                     element_size: Size::from_bytes(1),
                     count: 0
                 }
@@ -1340,6 +1368,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 assert!(discr_max >= 0);
                 let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
                 let mut align = dl.aggregate_align;
+                let mut primitive_align = dl.aggregate_align;
                 let mut size = Size::from_bytes(0);
 
                 // We're interested in the smallest alignment, so start large.
@@ -1369,6 +1398,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     }
                     size = cmp::max(size, st.min_size);
                     align = align.max(st.align);
+                    primitive_align = primitive_align.max(st.primitive_align);
                     Ok(st)
                 }).collect::<Result<Vec<_>, _>>()?;
 
@@ -1435,13 +1465,14 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     discr: ity,
                     variants: variants,
                     size: size,
-                    align: align
+                    align: align,
+                    primitive_align: primitive_align
                 }
             }
 
             // Types with no meaningful known layout.
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     return Err(LayoutError::Unknown(ty));
                 }
@@ -1557,6 +1588,30 @@ pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
         }
     }
 
+    /// Returns alignment before repr alignment is applied
+    pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align {
+        match *self {
+            Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align,
+            Univariant { ref variant, .. } |
+            StructWrappedNullablePointer { nonnull: ref variant, .. } => {
+                variant.primitive_align
+            },
+
+            _ => self.align(dl)
+        }
+    }
+
+    /// Returns repr alignment if it is greater than the primitive alignment.
+    pub fn over_align(&self, dl: &TargetDataLayout) -> Option<u32> {
+        let align = self.align(dl);
+        let primitive_align = self.primitive_align(dl);
+        if align.abi() > primitive_align.abi() {
+            Some(align.abi() as u32)
+        } else {
+            None
+        }
+    }
+
     pub fn field_offset<C: HasDataLayout>(&self,
                                           cx: C,
                                           i: usize,
@@ -1735,7 +1790,7 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     Err(err)
                 } else {
@@ -1805,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
     type TyLayout;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
 }
 
 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);
+        let ty = self.normalize_projections(ty);
 
         Ok(TyLayout {
             ty: ty,
@@ -1819,6 +1875,25 @@ fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
             variant_index: None
         })
     }
+
+    fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
+        if !ty.has_projection_types() {
+            return ty;
+        }
+
+        let mut selcx = traits::SelectionContext::new(self);
+        let cause = traits::ObligationCause::dummy();
+        let traits::Normalized { value: result, obligations } =
+            traits::normalize(&mut selcx, cause, &ty);
+
+        let mut fulfill_cx = traits::FulfillmentContext::new();
+
+        for obligation in obligations {
+            fulfill_cx.register_predicate_obligation(self, obligation);
+        }
+
+        self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
+    }
 }
 
 impl<'a, 'tcx> TyLayout<'tcx> {
@@ -1942,6 +2017,6 @@ pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
     }
 
     pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
-        cx.layout_of(self.field_type(cx, i))
+        cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
     }
 }
index e9eb5e97582bf136975d6332cb6e1925a17ebd62..4595a8c4f7784161715db667abad9c2bd50c3040 100644 (file)
 
 use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use hir;
 use middle::const_val;
 use middle::privacy::AccessLevels;
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::subst::Substs;
 use util::nodemap::NodeSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -73,6 +75,15 @@ fn default_span(&self, tcx: TyCtxt) -> Span {
     }
 }
 
+impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
@@ -96,6 +107,13 @@ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
     }
 }
 
+
+impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
+    fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        Self::empty()
+    }
+}
+
 pub struct CycleError<'a, 'tcx: 'a> {
     span: Span,
     cycle: RefMut<'a, [(Span, Query<'tcx>)]>,
@@ -216,6 +234,13 @@ fn describe(_: TyCtxt, _: CrateNum) -> String {
     }
 }
 
+impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
+    fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String {
+        format!("const-evaluating `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
 macro_rules! define_maps {
     (<$tcx:tt>
      $($(#[$attr:meta])*
@@ -378,7 +403,11 @@ fn default() -> Self {
     pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
     pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
     pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
-    pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
+    pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
+    pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
+
+    /// True if this is a foreign item (i.e., linked via `extern { ... }`).
+    pub is_foreign_item: IsForeignItem(DefId) -> bool,
 
     /// Maps from def-id of a type or region parameter to its
     /// (inferred) variance.
@@ -391,6 +420,7 @@ fn default() -> Self {
     pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
 
     pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+    pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity,
 
     /// Maps a DefId of a type to a list of its inherent impls.
     /// Contains implementations of methods that are inherent to a type.
@@ -441,16 +471,17 @@ fn default() -> Self {
     /// (Defined only for LOCAL_CRATE)
     pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
 
-    /// Results of evaluating monomorphic constants embedded in
-    /// other items, such as enum variant explicit discriminants.
-    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>,
+    /// Results of evaluating const items or constants embedded in
+    /// other items (such as enum variant explicit discriminants).
+    pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
+        -> const_val::EvalResult<'tcx>,
 
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
-    pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet,
+    pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
 
-    pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
+    pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -465,10 +496,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::Reachability
 }
 
-fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
+fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
     instance.dep_node()
 }
 
 fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::TypeckBodiesKrate
 }
+
+fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
+    DepNode::ConstEval(def_id)
+}
index ab1a06aeacd182990a362773cf9db929a911cccb..6a00586a01f82ad1bf6fea2f77cae58f1f7fdff2 100644 (file)
 use ty::subst::{Subst, Substs};
 use ty::util::IntTypeExt;
 use ty::walk::TypeWalker;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
+use util::common::ErrorReported;
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
 
 use serialize::{self, Encodable, Encoder};
-use std::borrow::Cow;
 use std::cell::{Cell, RefCell, Ref};
 use std::collections::BTreeMap;
+use std::cmp;
 use std::hash::{Hash, Hasher};
+use std::iter::FromIterator;
 use std::ops::Deref;
 use std::rc::Rc;
 use std::slice;
@@ -71,7 +73,6 @@
 pub use self::sty::Region::*;
 pub use self::sty::TypeVariants::*;
 
-pub use self::contents::TypeContents;
 pub use self::context::{TyCtxt, GlobalArenas, tls};
 pub use self::context::{Lift, TypeckTables};
 
 pub mod wf;
 pub mod util;
 
-mod contents;
 mod context;
 mod flags;
 mod instance;
 #[derive(Clone)]
 pub struct CrateAnalysis {
     pub access_levels: Rc<AccessLevels>,
-    pub reachable: NodeSet,
+    pub reachable: Rc<NodeSet>,
     pub name: String,
     pub glob_map: Option<hir::GlobMap>,
 }
@@ -425,6 +425,10 @@ pub enum FragmentInfo {
         const IS_SIZED          = 1 << 17,
         const MOVENESS_CACHED   = 1 << 18,
         const MOVES_BY_DEFAULT  = 1 << 19,
+        const FREEZENESS_CACHED = 1 << 20,
+        const IS_FREEZE         = 1 << 21,
+        const NEEDS_DROP_CACHED = 1 << 22,
+        const NEEDS_DROP        = 1 << 23,
     }
 }
 
@@ -1181,6 +1185,9 @@ pub struct ParameterEnvironment<'tcx> {
 
     /// A cache for `type_is_sized`
     pub is_sized_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
+
+    /// A cache for `type_is_freeze`
+    pub is_freeze_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
 }
 
 impl<'a, 'tcx> ParameterEnvironment<'tcx> {
@@ -1195,6 +1202,7 @@ pub fn with_caller_bounds(&self,
             free_id_outlive: self.free_id_outlive,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
+            is_freeze_cache: RefCell::new(FxHashMap()),
         }
     }
 
@@ -1326,17 +1334,6 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
 pub struct Destructor {
     /// The def-id of the destructor method
     pub did: DefId,
-    /// Invoking the destructor of a dtorck type during usual cleanup
-    /// (e.g. the glue emitted for stack unwinding) requires all
-    /// lifetimes in the type-structure of `adt` to strictly outlive
-    /// the adt value itself.
-    ///
-    /// If `adt` is not dtorck, then the adt's destructor can be
-    /// invoked even when there are lifetimes in the type-structure of
-    /// `adt` that do not strictly outlive the adt value itself.
-    /// (This allows programs to make cyclic structures without
-    /// resorting to unsafe means; see RFCs 769 and 1238).
-    pub is_dtorck: bool,
 }
 
 bitflags! {
@@ -1464,10 +1461,12 @@ pub enum AdtKind { Struct, Union, Enum }
 #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
 pub struct ReprOptions {
     pub int: Option<attr::IntType>,
+    pub align: u16,
     pub flags: ReprFlags,
 }
 
 impl_stable_hash_for!(struct ReprOptions {
+    align,
     int,
     flags
 });
@@ -1476,7 +1475,7 @@ impl ReprOptions {
     pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut flags = ReprFlags::empty();
         let mut size = None;
-
+        let mut max_align = 0;
         for attr in tcx.get_attrs(did).iter() {
             for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
                 flags.insert(match r {
@@ -1487,6 +1486,10 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
                         size = Some(i);
                         ReprFlags::empty()
                     },
+                    attr::ReprAlign(align) => {
+                        max_align = cmp::max(align, max_align);
+                        ReprFlags::empty()
+                    },
                 });
             }
         }
@@ -1500,7 +1503,7 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) {
             flags.insert(ReprFlags::IS_LINEAR);
         }
-        ReprOptions { int: size, flags: flags }
+        ReprOptions { int: size, align: max_align, flags: flags }
     }
 
     #[inline]
@@ -1597,14 +1600,6 @@ pub fn variant_descr(&self) -> &'static str {
         }
     }
 
-    /// Returns whether this is a dtorck type. If this returns
-    /// true, this type being safe for destruction requires it to be
-    /// alive; Otherwise, only the contents are required to be.
-    #[inline]
-    pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
-        self.destructor(tcx).map_or(false, |d| d.is_dtorck)
-    }
-
     /// Returns whether this type is #[fundamental] for the purposes
     /// of coherence checking.
     #[inline]
@@ -1681,6 +1676,7 @@ pub fn variant_of_def(&self, def: Def) -> &VariantDef {
         }
     }
 
+    #[inline]
     pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                          -> impl Iterator<Item=ConstInt> + 'a {
         let repr_type = self.repr.discr_type();
@@ -1689,11 +1685,18 @@ pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
         self.variants.iter().map(move |v| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
             if let VariantDiscr::Explicit(expr_did) = v.discr {
-                match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                let substs = Substs::empty();
+                match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                     Ok(ConstVal::Integral(v)) => {
                         discr = v;
                     }
-                    _ => {}
+                    err => {
+                        if !expr_did.is_local() {
+                            span_bug!(tcx.def_span(expr_did),
+                                "variant discriminant evaluation succeeded \
+                                 in its crate but failed locally: {:?}", err);
+                        }
+                    }
                 }
             }
             prev_discr = Some(discr);
@@ -1721,12 +1724,21 @@ pub fn discriminant_for_variant(&self,
                     explicit_index -= distance;
                 }
                 ty::VariantDiscr::Explicit(expr_did) => {
-                    match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                    let substs = Substs::empty();
+                    match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                         Ok(ConstVal::Integral(v)) => {
                             explicit_value = v;
                             break;
                         }
-                        _ => {
+                        err => {
+                            if !expr_did.is_local() {
+                                span_bug!(tcx.def_span(expr_did),
+                                    "variant discriminant evaluation succeeded \
+                                     in its crate but failed locally: {:?}", err);
+                            }
+                            if explicit_index == 0 {
+                                break;
+                            }
                             explicit_index -= 1;
                         }
                     }
@@ -1751,16 +1763,9 @@ pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
         queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
     }
 
-    /// Returns a simpler type such that `Self: Sized` if and only
+    /// Returns a list of types such that `Self: Sized` if and only
     /// if that type is Sized, or `TyErr` if this type is recursive.
     ///
-    /// HACK: instead of returning a list of types, this function can
-    /// return a tuple. In that case, the result is Sized only if
-    /// all elements of the tuple are Sized.
-    ///
-    /// This is generally the `struct_tail` if this is a struct, or a
-    /// tuple of them if this is an enum.
-    ///
     /// Oddly enough, checking that the sized-constraint is Sized is
     /// actually more expressive than checking all members:
     /// the Sized trait is inductive, so an associated type that references
@@ -1768,16 +1773,16 @@ pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
     ///
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer, e.g. issue #31299.
-    pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+    pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] {
         match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) {
-            Ok(ty) => ty,
+            Ok(tys) => tys,
             Err(_) => {
                 debug!("adt_sized_constraint: {:?} is recursive", self);
                 // This should be reported as an error by `check_representable`.
                 //
                 // Consider the type as Sized in the meanwhile to avoid
                 // further errors.
-                tcx.types.err
+                tcx.intern_type_list(&[tcx.types.err])
             }
         }
     }
@@ -1807,18 +1812,13 @@ fn sized_constraint_for_ty(&self,
 
             TyAdt(adt, substs) => {
                 // recursive case
-                let adt_ty =
-                    adt.sized_constraint(tcx)
-                       .subst(tcx, substs);
+                let adt_tys = adt.sized_constraint(tcx);
                 debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
-                       ty, adt_ty);
-                if let ty::TyTuple(ref tys, _) = adt_ty.sty {
-                    tys.iter().flat_map(|ty| {
-                        self.sized_constraint_for_ty(tcx, ty)
-                    }).collect()
-                } else {
-                    self.sized_constraint_for_ty(tcx, adt_ty)
-                }
+                       ty, adt_tys);
+                adt_tys.iter()
+                    .map(|ty| ty.subst(tcx, substs))
+                    .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty))
+                    .collect()
             }
 
             TyProjection(..) | TyAnon(..) => {
@@ -2023,6 +2023,23 @@ pub fn to_user_str(&self) -> &'static str {
     }
 }
 
+#[derive(Debug, Clone)]
+pub enum Attributes<'gcx> {
+    Owned(Rc<[ast::Attribute]>),
+    Borrowed(&'gcx [ast::Attribute])
+}
+
+impl<'gcx> ::std::ops::Deref for Attributes<'gcx> {
+    type Target = [ast::Attribute];
+
+    fn deref(&self) -> &[ast::Attribute] {
+        match self {
+            &Attributes::Owned(ref data) => &data,
+            &Attributes::Borrowed(data) => data
+        }
+    }
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> {
         self.item_tables(self.hir.body_owner_def_id(body))
@@ -2120,14 +2137,7 @@ pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
     }
 
     pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity {
-        if let Some(id) = self.hir.as_local_node_id(id) {
-            match self.hir.expect_item(id).node {
-                hir::ItemImpl(_, polarity, ..) => polarity,
-                ref item => bug!("trait_impl_polarity: {:?} not an impl", item)
-            }
-        } else {
-            self.sess.cstore.impl_polarity(id)
-        }
+        queries::impl_polarity::get(self, DUMMY_SP, id)
     }
 
     pub fn trait_relevant_for_never(self, did: DefId) -> bool {
@@ -2146,6 +2156,7 @@ pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
 
     fn associated_item_from_trait_item_ref(self,
                                            parent_def_id: DefId,
+                                           parent_vis: &hir::Visibility,
                                            trait_item_ref: &hir::TraitItemRef)
                                            -> AssociatedItem {
         let def_id = self.hir.local_def_id(trait_item_ref.id.node_id);
@@ -2160,7 +2171,8 @@ fn associated_item_from_trait_item_ref(self,
         AssociatedItem {
             name: trait_item_ref.name,
             kind: kind,
-            vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
+            // Visibility of trait items is inherited from their traits.
+            vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self),
             defaultness: trait_item_ref.defaultness,
             def_id: def_id,
             container: TraitContainer(parent_def_id),
@@ -2170,7 +2182,6 @@ fn associated_item_from_trait_item_ref(self,
 
     fn associated_item_from_impl_item_ref(self,
                                           parent_def_id: DefId,
-                                          from_trait_impl: bool,
                                           impl_item_ref: &hir::ImplItemRef)
                                           -> AssociatedItem {
         let def_id = self.hir.local_def_id(impl_item_ref.id.node_id);
@@ -2182,14 +2193,11 @@ fn associated_item_from_impl_item_ref(self,
             hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
         };
 
-        // Trait impl items are always public.
-        let public = hir::Public;
-        let vis = if from_trait_impl { &public } else { &impl_item_ref.vis };
-
         ty::AssociatedItem {
             name: impl_item_ref.name,
             kind: kind,
-            vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
+            // Visibility of trait impl items doesn't matter.
+            vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self),
             defaultness: impl_item_ref.defaultness,
             def_id: def_id,
             container: ImplContainer(parent_def_id),
@@ -2375,46 +2383,12 @@ pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
         Some(self.item_mir(did))
     }
 
-    /// If `type_needs_drop` returns true, then `ty` is definitely
-    /// non-copy and *might* have a destructor attached; if it returns
-    /// false, then `ty` definitely has no destructor (i.e. no drop glue).
-    ///
-    /// (Note that this implies that if `ty` has a destructor attached,
-    /// then `type_needs_drop` will definitely return `true` for `ty`.)
-    pub fn type_needs_drop_given_env(self,
-                                     ty: Ty<'gcx>,
-                                     param_env: &ty::ParameterEnvironment<'gcx>) -> bool {
-        // Issue #22536: We first query type_moves_by_default.  It sees a
-        // normalized version of the type, and therefore will definitely
-        // know whether the type implements Copy (and thus needs no
-        // cleanup/drop/zeroing) ...
-        let tcx = self.global_tcx();
-        let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP);
-
-        if implements_copy { return false; }
-
-        // ... (issue #22536 continued) but as an optimization, still use
-        // prior logic of asking if the `needs_drop` bit is set; we need
-        // not zero non-Copy types if they have no destructor.
-
-        // FIXME(#22815): Note that calling `ty::type_contents` is a
-        // conservative heuristic; it may report that `needs_drop` is set
-        // when actual type does not actually have a destructor associated
-        // with it. But since `ty` absolutely did not have the `Copy`
-        // bound attached (see above), it is sound to treat it as having a
-        // destructor (e.g. zero its memory on move).
-
-        let contents = ty.type_contents(tcx);
-        debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
-        contents.needs_drop(tcx)
-    }
-
     /// Get the attributes of a definition.
-    pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> {
+    pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> {
         if let Some(id) = self.hir.as_local_node_id(did) {
-            Cow::Borrowed(self.hir.attrs(id))
+            Attributes::Borrowed(self.hir.attrs(id))
         } else {
-            Cow::Owned(self.sess.cstore.item_attrs(did))
+            Attributes::Owned(self.sess.cstore.item_attrs(did))
         }
     }
 
@@ -2520,17 +2494,16 @@ pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
     /// Construct a parameter environment suitable for static contexts or other contexts where there
     /// are no free type/lifetime parameters in scope.
     pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
-
-        // for an empty parameter environment, there ARE no free
-        // regions, so it shouldn't matter what we use for the free id
-        let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
         ty::ParameterEnvironment {
             free_substs: self.intern_substs(&[]),
             caller_bounds: Vec::new(),
-            implicit_region_bound: self.mk_region(ty::ReEmpty),
-            free_id_outlive: free_id_outlive,
+            implicit_region_bound: self.types.re_empty,
+            // for an empty parameter environment, there ARE no free
+            // regions, so it shouldn't matter what we use for the free id
+            free_id_outlive: ROOT_CODE_EXTENT,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
+            is_freeze_cache: RefCell::new(FxHashMap()),
         }
     }
 
@@ -2603,6 +2576,7 @@ pub fn construct_parameter_environment(self,
             free_id_outlive: free_id_outlive,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
+            is_freeze_cache: RefCell::new(FxHashMap()),
         };
 
         let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
@@ -2663,12 +2637,10 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     let parent_def_id = tcx.hir.local_def_id(parent_id);
     let parent_item = tcx.hir.expect_item(parent_id);
     match parent_item.node {
-        hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => {
+        hir::ItemImpl(.., ref impl_item_refs) => {
             if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) {
-                let assoc_item =
-                    tcx.associated_item_from_impl_item_ref(parent_def_id,
-                                                            impl_trait_ref.is_some(),
-                                                            impl_item_ref);
+                let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id,
+                                                                        impl_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -2676,8 +2648,9 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 
         hir::ItemTrait(.., ref trait_item_refs) => {
             if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) {
-                let assoc_item =
-                    tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
+                let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id,
+                                                                         &parent_item.vis,
+                                                                         trait_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -2692,13 +2665,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 
 /// Calculates the Sized-constraint.
 ///
-/// As the Sized-constraint of enums can be a *set* of types,
-/// the Sized-constraint may need to be a set also. Because introducing
-/// a new type of IVar is currently a complex affair, the Sized-constraint
-/// may be a tuple.
-///
-/// In fact, there are only a few options for the constraint:
-///     - `bool`, if the type is always Sized
+/// In fact, there are only a few options for the types in the constraint:
 ///     - an obviously-unsized type
 ///     - a type parameter or projection whose Sizedness can't be known
 ///     - a tuple of type parameters or projections, if there are multiple
@@ -2707,26 +2674,50 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 ///       check should catch this case.
 fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   def_id: DefId)
-                                  -> Ty<'tcx> {
+                                  -> &'tcx [Ty<'tcx>] {
     let def = tcx.lookup_adt_def(def_id);
 
-    let tys: Vec<_> = def.variants.iter().flat_map(|v| {
+    let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| {
         v.fields.last()
     }).flat_map(|f| {
-        let ty = tcx.item_type(f.did);
-        def.sized_constraint_for_ty(tcx, ty)
-    }).collect();
-
-    let ty = match tys.len() {
-        _ if tys.references_error() => tcx.types.err,
-        0 => tcx.types.bool,
-        1 => tys[0],
-        _ => tcx.intern_tup(&tys[..], false)
-    };
+        def.sized_constraint_for_ty(tcx, tcx.item_type(f.did))
+    }).collect::<Vec<_>>());
 
-    debug!("adt_sized_constraint: {:?} => {:?}", def, ty);
+    debug!("adt_sized_constraint: {:?} => {:?}", def, result);
 
-    ty
+    result
+}
+
+/// Calculates the dtorck constraint for a type.
+fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   def_id: DefId)
+                                   -> DtorckConstraint<'tcx> {
+    let def = tcx.lookup_adt_def(def_id);
+    let span = tcx.def_span(def_id);
+    debug!("dtorck_constraint: {:?}", def);
+
+    if def.is_phantom_data() {
+        let result = DtorckConstraint {
+            outlives: vec![],
+            dtorck_types: vec![
+                tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0])
+           ]
+        };
+        debug!("dtorck_constraint: {:?} => {:?}", def, result);
+        return result;
+    }
+
+    let mut result = def.all_fields()
+        .map(|field| tcx.item_type(field.did))
+        .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty))
+        .collect::<Result<DtorckConstraint, ErrorReported>>()
+        .unwrap_or(DtorckConstraint::empty());
+    result.outlives.extend(tcx.destructor_constraints(def));
+    result.dedup();
+
+    debug!("dtorck_constraint: {:?} => {:?}", def, result);
+
+    result
 }
 
 fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -2757,6 +2748,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         associated_item,
         associated_item_def_ids,
         adt_sized_constraint,
+        adt_dtorck_constraint,
         ..*providers
     };
 }
@@ -2764,6 +2756,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
 pub fn provide_extern(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         adt_sized_constraint,
+        adt_dtorck_constraint,
         ..*providers
     };
 }
@@ -2780,3 +2773,45 @@ pub struct CrateInherentImpls {
     pub inherent_impls: DefIdMap<Rc<Vec<DefId>>>,
 }
 
+/// A set of constraints that need to be satisfied in order for
+/// a type to be valid for destruction.
+#[derive(Clone, Debug)]
+pub struct DtorckConstraint<'tcx> {
+    /// Types that are required to be alive in order for this
+    /// type to be valid for destruction.
+    pub outlives: Vec<ty::subst::Kind<'tcx>>,
+    /// Types that could not be resolved: projections and params.
+    pub dtorck_types: Vec<Ty<'tcx>>,
+}
+
+impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
+{
+    fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(iter: I) -> Self {
+        let mut result = Self::empty();
+
+        for constraint in iter {
+            result.outlives.extend(constraint.outlives);
+            result.dtorck_types.extend(constraint.dtorck_types);
+        }
+
+        result
+    }
+}
+
+
+impl<'tcx> DtorckConstraint<'tcx> {
+    fn empty() -> DtorckConstraint<'tcx> {
+        DtorckConstraint {
+            outlives: vec![],
+            dtorck_types: vec![]
+        }
+    }
+
+    fn dedup<'a>(&mut self) {
+        let mut outlives = FxHashSet();
+        let mut dtorck_types = FxHashSet();
+
+        self.outlives.retain(|&val| outlives.replace(val).is_none());
+        self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
+    }
+}
index 0a2cc1c30f40fc61452b3aa8bd3fedd3386269c9..14aebdf8418fe58c1565847c12d69a0e82d9c5fd 100644 (file)
@@ -539,6 +539,9 @@ fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
     }
 
     fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region {
+        if self.region_binders_passed == 0 || !region.has_escaping_regions() {
+            return region;
+        }
         self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
     }
 }
index 5334ee2835db2325f6bcbf4066069efb6ad7c1a9..f68cf6f97f857d77bf9bfcaf2e7c516d79035f6a 100644 (file)
 use ty::ParameterEnvironment;
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
+use ty::subst::{Subst, Kind};
 use ty::TypeVariants::*;
 use util::common::ErrorReported;
-use util::nodemap::FxHashMap;
+use util::nodemap::{FxHashMap, FxHashSet};
 use middle::lang_items;
 
 use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
@@ -385,6 +386,27 @@ pub fn calculate_dtor(
             None => return None,
         };
 
+        Some(ty::Destructor { did: dtor_did })
+    }
+
+    /// Return the set of types that are required to be alive in
+    /// order to run the destructor of `def` (see RFCs 769 and
+    /// 1238).
+    ///
+    /// Note that this returns only the constraints for the
+    /// destructor of `def` itself. For the destructors of the
+    /// contents, you need `adt_dtorck_constraint`.
+    pub fn destructor_constraints(self, def: &'tcx ty::AdtDef)
+                                  -> Vec<ty::subst::Kind<'tcx>>
+    {
+        let dtor = match def.destructor(self) {
+            None => {
+                debug!("destructor_constraints({:?}) - no dtor", def.did);
+                return vec![]
+            }
+            Some(dtor) => dtor.did
+        };
+
         // RFC 1238: if the destructor method is tagged with the
         // attribute `unsafe_destructor_blind_to_params`, then the
         // compiler is being instructed to *assume* that the
@@ -394,11 +416,147 @@ pub fn calculate_dtor(
         // Such access can be in plain sight (e.g. dereferencing
         // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
         // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
-        let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params");
-        Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck })
+        if self.has_attr(dtor, "unsafe_destructor_blind_to_params") {
+            debug!("destructor_constraint({:?}) - blind", def.did);
+            return vec![];
+        }
+
+        let impl_def_id = self.associated_item(dtor).container.id();
+        let impl_generics = self.item_generics(impl_def_id);
+
+        // We have a destructor - all the parameters that are not
+        // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute)
+        // must be live.
+
+        // We need to return the list of parameters from the ADTs
+        // generics/substs that correspond to impure parameters on the
+        // impl's generics. This is a bit ugly, but conceptually simple:
+        //
+        // Suppose our ADT looks like the following
+        //
+        //     struct S<X, Y, Z>(X, Y, Z);
+        //
+        // and the impl is
+        //
+        //     impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0>
+        //
+        // We want to return the parameters (X, Y). For that, we match
+        // up the item-substs <X, Y, Z> with the substs on the impl ADT,
+        // <P1, P2, P0>, and then look up which of the impl substs refer to
+        // parameters marked as pure.
+
+        let impl_substs = match self.item_type(impl_def_id).sty {
+            ty::TyAdt(def_, substs) if def_ == def => substs,
+            _ => bug!()
+        };
+
+        let item_substs = match self.item_type(def.did).sty {
+            ty::TyAdt(def_, substs) if def_ == def => substs,
+            _ => bug!()
+        };
+
+        let result = item_substs.iter().zip(impl_substs.iter())
+            .filter(|&(_, &k)| {
+                if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() {
+                    !impl_generics.region_param(ebr).pure_wrt_drop
+                } else if let Some(&ty::TyS {
+                    sty: ty::TypeVariants::TyParam(ref pt), ..
+                }) = k.as_type() {
+                    !impl_generics.type_param(pt).pure_wrt_drop
+                } else {
+                    // not a type or region param - this should be reported
+                    // as an error.
+                    false
+                }
+            }).map(|(&item_param, _)| item_param).collect();
+        debug!("destructor_constraint({:?}) = {:?}", def.did, result);
+        result
+    }
+
+    /// Return a set of constraints that needs to be satisfied in
+    /// order for `ty` to be valid for destruction.
+    pub fn dtorck_constraint_for_ty(self,
+                                    span: Span,
+                                    for_ty: Ty<'tcx>,
+                                    depth: usize,
+                                    ty: Ty<'tcx>)
+                                    -> Result<ty::DtorckConstraint<'tcx>, ErrorReported>
+    {
+        debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
+               span, for_ty, depth, ty);
+
+        if depth >= self.sess.recursion_limit.get() {
+            let mut err = struct_span_err!(
+                self.sess, span, E0320,
+                "overflow while adding drop-check rules for {}", for_ty);
+            err.note(&format!("overflowed on {}", ty));
+            err.emit();
+            return Err(ErrorReported);
+        }
+
+        let result = match ty.sty {
+            ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
+            ty::TyFloat(_) | ty::TyStr | ty::TyNever |
+            ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+                // these types never have a destructor
+                Ok(ty::DtorckConstraint::empty())
+            }
+
+            ty::TyArray(ety, _) | ty::TySlice(ety) => {
+                // single-element containers, behave like their element
+                self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety)
+            }
+
+            ty::TyTuple(tys, _) => {
+                tys.iter().map(|ty| {
+                    self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
+                }).collect()
+            }
+
+            ty::TyClosure(def_id, substs) => {
+                substs.upvar_tys(def_id, self).map(|ty| {
+                    self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
+                }).collect()
+            }
+
+            ty::TyAdt(def, substs) => {
+                let ty::DtorckConstraint {
+                    dtorck_types, outlives
+                } = ty::queries::adt_dtorck_constraint::get(self, span, def.did);
+                Ok(ty::DtorckConstraint {
+                    // FIXME: we can try to recursively `dtorck_constraint_on_ty`
+                    // there, but that needs some way to handle cycles.
+                    dtorck_types: dtorck_types.subst(self, substs),
+                    outlives: outlives.subst(self, substs)
+                })
+            }
+
+            // Objects must be alive in order for their destructor
+            // to be called.
+            ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
+                outlives: vec![Kind::from(ty)],
+                dtorck_types: vec![],
+            }),
+
+            // Types that can't be resolved. Pass them forward.
+            ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => {
+                Ok(ty::DtorckConstraint {
+                    outlives: vec![],
+                    dtorck_types: vec![ty],
+                })
+            }
+
+            ty::TyInfer(..) | ty::TyError => {
+                self.sess.delay_span_bug(span, "unresolved type in dtorck");
+                Err(ErrorReported)
+            }
+        };
+
+        debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
+        result
     }
 
-    pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
+    pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
             def_id = self.parent_def_id(def_id).unwrap_or_else(|| {
@@ -412,7 +570,7 @@ pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
     /// a suitable "empty substs" for it.
     pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> {
         ty::Substs::for_item(self, item_def_id,
-                             |_, _| self.mk_region(ty::ReErased),
+                             |_, _| self.types.re_erased,
                              |_, _| {
             bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
         })
@@ -655,6 +813,165 @@ fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         result
     }
 
+    /// Returns `true` if and only if there are no `UnsafeCell`s
+    /// nested within the type (ignoring `PhantomData` or pointers).
+    #[inline]
+    pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     param_env: &ParameterEnvironment<'tcx>,
+                     span: Span) -> bool
+    {
+        if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) {
+            return self.flags.get().intersects(TypeFlags::IS_FREEZE);
+        }
+
+        self.is_freeze_uncached(tcx, param_env, span)
+    }
+
+    fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          param_env: &ParameterEnvironment<'tcx>,
+                          span: Span) -> bool {
+        assert!(!self.needs_infer());
+
+        // Fast-path for primitive types
+        let result = match self.sty {
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
+            TyStr | TyNever => Some(true),
+
+            TyArray(..) | TySlice(_) |
+            TyTuple(..) | TyClosure(..) | TyAdt(..) |
+            TyDynamic(..) | TyProjection(..) | TyParam(..) |
+            TyInfer(..) | TyAnon(..) | TyError => None
+        }.unwrap_or_else(|| {
+            self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem),
+                              &param_env.is_freeze_cache, span) });
+
+        if !self.has_param_types() && !self.has_self_ty() {
+            self.flags.set(self.flags.get() | if result {
+                TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE
+            } else {
+                TypeFlags::FREEZENESS_CACHED
+            });
+        }
+
+        result
+    }
+
+    /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
+    /// non-copy and *might* have a destructor attached; if it returns
+    /// `false`, then `ty` definitely has no destructor (i.e. no drop glue).
+    ///
+    /// (Note that this implies that if `ty` has a destructor attached,
+    /// then `needs_drop` will definitely return `true` for `ty`.)
+    #[inline]
+    pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    param_env: &ty::ParameterEnvironment<'tcx>) -> bool {
+        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
+            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
+        }
+
+        self.needs_drop_uncached(tcx, param_env, &mut FxHashSet())
+    }
+
+    fn needs_drop_inner(&'tcx self,
+                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        param_env: &ty::ParameterEnvironment<'tcx>,
+                        stack: &mut FxHashSet<Ty<'tcx>>)
+                        -> bool {
+        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
+            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
+        }
+
+        // This should be reported as an error by `check_representable`.
+        //
+        // Consider the type as not needing drop in the meanwhile to avoid
+        // further errors.
+        if let Some(_) = stack.replace(self) {
+            return false;
+        }
+
+        let needs_drop = self.needs_drop_uncached(tcx, param_env, stack);
+
+        // "Pop" the cycle detection "stack".
+        stack.remove(self);
+
+        needs_drop
+    }
+
+    fn needs_drop_uncached(&'tcx self,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           param_env: &ty::ParameterEnvironment<'tcx>,
+                           stack: &mut FxHashSet<Ty<'tcx>>)
+                           -> bool {
+        assert!(!self.needs_infer());
+
+        let result = match self.sty {
+            // Fast-path for primitive types
+            ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+            ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+            ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
+
+            // Issue #22536: We first query type_moves_by_default.  It sees a
+            // normalized version of the type, and therefore will definitely
+            // know whether the type implements Copy (and thus needs no
+            // cleanup/drop/zeroing) ...
+            _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false,
+
+            // ... (issue #22536 continued) but as an optimization, still use
+            // prior logic of asking for the structural "may drop".
+
+            // FIXME(#22815): Note that this is a conservative heuristic;
+            // it may report that the type "may drop" when actual type does
+            // not actually have a destructor associated with it. But since
+            // the type absolutely did not have the `Copy` bound attached
+            // (see above), it is sound to treat it as having a destructor.
+
+            // User destructors are the only way to have concrete drop types.
+            ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
+
+            // Can refer to a type which may drop.
+            // FIXME(eddyb) check this against a ParameterEnvironment.
+            ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
+            ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
+
+            // Structural recursion.
+            ty::TyArray(ty, _) | ty::TySlice(ty) => {
+                ty.needs_drop_inner(tcx, param_env, stack)
+            }
+
+            ty::TyClosure(def_id, ref substs) => {
+                substs.upvar_tys(def_id, tcx)
+                    .any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
+            }
+
+            ty::TyTuple(ref tys, _) => {
+                tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
+            }
+
+            // unions don't have destructors regardless of the child types
+            ty::TyAdt(def, _) if def.is_union() => false,
+
+            ty::TyAdt(def, substs) => {
+                def.variants.iter().any(|v| {
+                    v.fields.iter().any(|f| {
+                        f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack)
+                    })
+                })
+            }
+        };
+
+        if !self.has_param_types() && !self.has_self_ty() {
+            self.flags.set(self.flags.get() | if result {
+                TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP
+            } else {
+                TypeFlags::NEEDS_DROP_CACHED
+            });
+        }
+
+        result
+    }
+
     #[inline]
     pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
                         -> Result<&'tcx Layout, LayoutError<'tcx>> {
index ca6894a7b70411ae74cb94db2d386f09bc0aa3ae..e60fdc386ce6ed90fa1f4a1f7441bdc557e2cb87 100644 (file)
@@ -162,6 +162,7 @@ fn $module() {
     ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
 
     ("i686-linux-android", i686_linux_android),
+    ("x86_64-linux-android", x86_64_linux_android),
     ("arm-linux-androideabi", arm_linux_androideabi),
     ("armv7-linux-androideabi", armv7_linux_androideabi),
     ("aarch64-linux-android", aarch64_linux_android),
diff --git a/src/librustc_back/target/x86_64_linux_android.rs b/src/librustc_back/target/x86_64_linux_android.rs
new file mode 100644 (file)
index 0000000..75cf3e1
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+use LinkerFlavor;
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::android_base::opts();
+    base.cpu = "x86-64".to_string();
+    // https://developer.android.com/ndk/guides/abis.html#86-64
+    base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+
+    Ok(Target {
+        llvm_target: "x86_64-linux-android".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "android".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
index bbfb7e5874ea0776d37a9504199acef93f79bfe4..b921678b495c2803c0e6063184bd02d0960e398f 100644 (file)
@@ -120,7 +120,7 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region {
             }
             Categorization::StaticItem |
             Categorization::Deref(.., mc::UnsafePtr(..)) => {
-                self.bccx.tcx.mk_region(ty::ReStatic)
+                self.bccx.tcx.types.re_static
             }
             Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
             Categorization::Deref(.., mc::Implicit(_, r)) => {
index dc01cbe5e7605eb3a4fd4a9e19e269d25fe531a8..de5613dbfaa38b183c8d34d4584c233191501805 100644 (file)
@@ -322,7 +322,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>(
         let ty = lvalue.ty(mir, tcx).to_ty(tcx);
         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty);
 
-        if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) {
+        if ty.needs_drop(tcx, &ctxt.param_env) {
             each_child(child);
         } else {
             debug!("on_all_drop_children_bits - skipping")
index 9c5a669bef0d92623aeb12488802a49f321c6cfe..e9352f53c92d68c724d5934465cc9ebe202a2abc 100644 (file)
@@ -15,7 +15,7 @@
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
@@ -48,110 +48,39 @@ macro_rules! math {
     }
 }
 
-fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  variant_def: DefId)
-                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
-    if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
-        let enum_node_id = tcx.hir.get_parent(variant_node_id);
-        if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
-            if let hir::ItemEnum(ref edef, _) = it.node {
-                for variant in &edef.variants {
-                    if variant.node.data.id() == variant_node_id {
-                        return variant.node.disr_expr.map(|e| {
-                            let def_id = tcx.hir.body_owner_def_id(e);
-                            (&tcx.hir.body(e).value,
-                             tcx.item_tables(def_id))
-                        });
-                    }
-                }
-            }
-        }
-    }
-    None
-}
-
 /// * `def_id` is the id of the constant.
 /// * `substs` is the monomorphized substitutions for the expression.
 ///
 /// `substs` is optional and is used for associated constants.
 /// This generally happens in late/trans const evaluation.
-pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        def_id: DefId,
-                                        substs: &'tcx Substs<'tcx>)
-                                        -> Option<(&'tcx Expr,
-                                                   &'a ty::TypeckTables<'tcx>)> {
+pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    def_id: DefId,
+                                    substs: &'tcx Substs<'tcx>)
+                                    -> Option<(DefId, &'tcx Substs<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
-            None => None,
-            Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(_, body), ..
-            })) |
-            Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(_, body), ..
-            })) => {
-                Some((&tcx.hir.body(body).value,
-                      tcx.item_tables(def_id)))
+            Some(hir_map::NodeTraitItem(_)) => {
+                // If we have a trait item and the substitutions for it,
+                // `resolve_trait_associated_const` will select an impl
+                // or the default.
+                resolve_trait_associated_const(tcx, def_id, substs)
             }
-            Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(_, default) => {
-                    // If we have a trait item and the substitutions for it,
-                    // `resolve_trait_associated_const` will select an impl
-                    // or the default.
-                    let trait_id = tcx.hir.get_parent(node_id);
-                    let trait_id = tcx.hir.local_def_id(trait_id);
-                    let default_value = default.map(|body| {
-                        (&tcx.hir.body(body).value,
-                            tcx.item_tables(def_id))
-                    });
-                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                }
-                _ => None
-            },
-            Some(_) => None
+            _ => Some((def_id, substs))
         }
     } else {
-        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, tcx.item_tables(def_id))
-        });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
-                let trait_id = tcx.sess.cstore.trait_of_item(def_id);
                 // As mentioned in the comments above for in-crate
                 // constants, we only try to find the expression for a
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
-                if let Some(trait_id) = trait_id {
-                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
-                                                   trait_id, substs)
+                if tcx.sess.cstore.trait_of_item(def_id).is_some() {
+                    resolve_trait_associated_const(tcx, def_id, substs)
                 } else {
-                    expr_and_tables
+                    Some((def_id, substs))
                 }
-            },
-            Some(Def::Const(..)) => expr_and_tables,
-            _ => None
-        }
-    }
-}
-
-fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
-{
-    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
-            if fn_like.constness() == hir::Constness::Const {
-                Some((tcx.hir.body(fn_like.body()),
-                      tcx.item_tables(def_id)))
-            } else {
-                None
             }
-        })
-    } else {
-        if tcx.sess.cstore.is_const_fn(def_id) {
-            tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, tcx.item_tables(def_id))
-            })
-        } else {
-            None
+            _ => Some((def_id, substs))
         }
     }
 }
@@ -338,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprCast(ref base, _) => {
-        match cast_const(tcx, cx.eval(base)?, ety) {
-            Ok(val) => val,
-            Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
+        let base_val = cx.eval(base)?;
+        let base_ty = cx.tables.expr_ty(base);
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let base_ty = if cx.substs.is_empty() {
+            base_ty
+        } else {
+            base_ty.subst(tcx, cx.substs)
+        };
+        if ety == base_ty {
+            base_val
+        } else {
+            match cast_const(tcx, base_val, ety) {
+                Ok(val) => val,
+                Err(kind) => signal!(e, kind),
+            }
         }
       }
       hir::ExprPath(ref qpath) => {
@@ -357,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, TypeckError);
-                  }
+                    match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) {
+                        Ok(val) => val,
+                        Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                            signal!(e, TypeckError);
+                        }
+                        Err(err) => {
+                            debug!("bad reference: {:?}, {:?}", err.description(), err.span);
+                            signal!(e, ErroneousReferencedConstant(box err))
+                        },
+                    }
               },
-              Def::VariantCtor(variant_def, ..) => {
-                  if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, UnimplementedConstVal("enum variants"));
-                  }
+              Def::VariantCtor(variant_def, CtorKind::Const) => {
+                Variant(variant_def)
+              }
+              Def::VariantCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("enum variants"));
               }
-              Def::StructCtor(..) => {
+              Def::StructCtor(_, CtorKind::Const) => {
                   ConstVal::Struct(Default::default())
               }
+              Def::StructCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("tuple struct constructors"))
+              }
               Def::Local(def_id) => {
                   debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
                   if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
@@ -407,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let (did, substs) = match cx.eval(callee)? {
-              Function(did, substs) => (did, substs),
-              Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
-              callee => signal!(e, CallOn(callee)),
+          let (def_id, substs) = match cx.eval(callee)? {
+              Function(def_id, substs) => (def_id, substs),
+              _ => signal!(e, TypeckError),
           };
-          let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
-              Some(x) => x,
-              None => signal!(e, NonConstPath),
+
+          let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
+            if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
+                if fn_like.constness() == hir::Constness::Const {
+                    tcx.hir.body(fn_like.body())
+                } else {
+                    signal!(e, TypeckError)
+                }
+            } else {
+                signal!(e, TypeckError)
+            }
+          } else {
+            if tcx.sess.cstore.is_const_fn(def_id) {
+                tcx.sess.cstore.item_body(tcx, def_id)
+            } else {
+                signal!(e, TypeckError)
+            }
           };
 
           let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
@@ -434,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           debug!("const call({:?})", call_args);
           let callee_cx = ConstContext {
             tcx: tcx,
-            tables: tables,
+            tables: tcx.item_tables(def_id),
             substs: substs,
             fn_args: Some(call_args)
           };
@@ -532,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
     Ok(result)
 }
 
-fn resolve_trait_associated_const<'a, 'tcx: 'a>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
-    trait_id: DefId,
-    rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
-{
-    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
+fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                            def_id: DefId,
+                                            substs: &'tcx Substs<'tcx>)
+                                            -> Option<(DefId, &'tcx Substs<'tcx>)> {
+    let trait_item = tcx.associated_item(def_id);
+    let trait_id = trait_item.container.id();
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_id);
     tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@@ -569,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
-                let name = tcx.associated_item(trait_item_id).name;
+                let name = trait_item.name;
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
-                    None => default_value,
+                    // FIXME(eddyb) Use proper Instance resolution to
+                    // get the correct Substs returned from here.
+                    Some(ic) => Some((ic.def_id, Substs::empty())),
+                    None => {
+                        if trait_item.defaultness.has_value() {
+                            Some((def_id, substs))
+                        } else {
+                            None
+                        }
+                    }
                 }
             }
             _ => {
@@ -615,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             U8(u) => Ok(Char(u as char)),
             _ => bug!(),
         },
-        _ => bug!(),
+        _ => Err(CannotCast),
     }
 }
 
@@ -659,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
         Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Variant(v) => {
+            let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap());
+            let idx = adt.variant_index_with_id(v);
+            cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
+        }
         Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
@@ -796,21 +748,35 @@ pub fn compare_lit_exprs(&self,
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
-        monomorphic_const_eval,
+        const_eval,
         ..*providers
     };
 }
 
-fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    def_id: DefId)
-                                    -> EvalResult<'tcx> {
-    let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
+fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        (def_id, substs): (DefId, &'tcx Substs<'tcx>))
+                        -> EvalResult<'tcx> {
+    let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) {
+        resolved
+    } else {
+        return Err(ConstEvalErr {
+            span: tcx.def_span(def_id),
+            kind: TypeckError
+        });
+    };
+
+    let cx = ConstContext {
+        tcx,
+        tables: tcx.item_tables(def_id),
+        substs: substs,
+        fn_args: None
+    };
 
     let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
         tcx.hir.body(tcx.hir.body_owned_by(id))
     } else {
-        tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
+        tcx.sess.cstore.item_body(tcx, def_id)
     };
     cx.eval(&body.value)
 }
index f20fa27dc225124eca4bd6cd00fa90128e7ffd5a..0dfafeb6fb8362b95c7f8af1fc0953307e12e18e 100644 (file)
@@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
         ConstVal::Bool(b) => write!(f, "{:?}", b),
         ConstVal::Char(c) => write!(f, "{:?}", c),
+        ConstVal::Variant(_) |
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
         ConstVal::Function(..) |
@@ -587,11 +588,16 @@ fn lower_path(&mut self,
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
                 match eval::lookup_const_by_id(tcx, def_id, substs) {
-                    Some((const_expr, const_tables)) => {
+                    Some((def_id, _substs)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables;
-                        let pat = self.lower_const_expr(const_expr, pat_id, span);
+                        self.tables = tcx.item_tables(def_id);
+                        let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+                            tcx.hir.body(tcx.hir.body_owned_by(id))
+                        } else {
+                            tcx.sess.cstore.item_body(tcx, def_id)
+                        };
+                        let pat = self.lower_const_expr(&body.value, pat_id, span);
                         self.tables = old_tables;
                         return pat;
                     }
@@ -615,7 +621,12 @@ fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
         match const_cx.eval(expr) {
             Ok(value) => {
-                PatternKind::Constant { value: value }
+                if let ConstVal::Variant(def_id) = value {
+                    let ty = self.tables.expr_ty(expr);
+                    self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
+                } else {
+                    PatternKind::Constant { value: value }
+                }
             }
             Err(e) => {
                 self.errors.push(PatternError::ConstEval(e));
index 7632b40ab4f9ead935148a64514c5ec9147268a7..438f482fa55c7bfbd90be456920f77f3edfbbbfd 100644 (file)
@@ -225,6 +225,8 @@ macro_rules! controller_entry_point {
         sess.code_stats.borrow().print_type_sizes();
     }
 
+    if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); }
+
     let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
 
     controller_entry_point!(after_llvm,
@@ -810,7 +812,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         defs: resolver.definitions,
         analysis: ty::CrateAnalysis {
             access_levels: Rc::new(AccessLevels::default()),
-            reachable: NodeSet(),
+            reachable: Rc::new(NodeSet()),
             name: crate_name.to_string(),
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
         },
@@ -889,9 +891,10 @@ macro_rules! try_with_f {
     let index = stability::Index::new(&hir_map);
 
     let mut local_providers = ty::maps::Providers::default();
+    borrowck::provide(&mut local_providers);
     mir::provide(&mut local_providers);
+    reachable::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
-    borrowck::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
index 7447fba3038eaeb151e0c4cacb1fe1aed0c95e72..147d6558e19cc31a12842f4af039d9d046e77c81 100644 (file)
@@ -343,12 +343,12 @@ pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> {
     }
 
     pub fn t_rptr_static(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic),
+        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static,
                                   self.tcx().types.isize)
     }
 
     pub fn t_rptr_empty(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty),
+        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty,
                                   self.tcx().types.isize)
     }
 
index a52628ceb47abf75382f84b1dda1b8247b18db1e..64652bb308bdc4952af117da586ff704648c68c6 100644 (file)
@@ -263,6 +263,41 @@ fn render_source_line(&self,
 
         draw_col_separator(buffer, line_offset, width_offset - 2);
 
+        // Special case when there's only one annotation involved, it is the start of a multiline
+        // span and there's no text at the beginning of the code line. Instead of doing the whole
+        // graph:
+        //
+        // 2 |   fn foo() {
+        //   |  _^
+        // 3 | |
+        // 4 | | }
+        //   | |_^ test
+        //
+        // we simplify the output to:
+        //
+        // 2 | / fn foo() {
+        // 3 | |
+        // 4 | | }
+        //   | |_^ test
+        if line.annotations.len() == 1 {
+            if let Some(ref ann) = line.annotations.get(0) {
+                if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
+                    if source_string[0..ann.start_col].trim() == "" {
+                        let style = if ann.is_primary {
+                            Style::UnderlinePrimary
+                        } else {
+                            Style::UnderlineSecondary
+                        };
+                        buffer.putc(line_offset,
+                                    width_offset + depth - 1,
+                                    '/',
+                                    style);
+                        return vec![(depth, style)];
+                    }
+                }
+            }
+        }
+
         // We want to display like this:
         //
         //      vec.push(vec.pop().unwrap());
@@ -355,10 +390,8 @@ fn render_source_line(&self,
         for (i, annotation) in annotations.iter().enumerate() {
             for (j, next) in annotations.iter().enumerate() {
                 if overlaps(next, annotation, 0)  // This label overlaps with another one and both
-                    && !annotation.is_line()      // take space (they have text and are not
-                    && !next.is_line()            // multiline lines).
-                    && annotation.has_label()
-                    && j > i
+                    && annotation.has_label()     // take space (they have text and are not
+                    && j > i                      // multiline lines).
                     && p == 0  // We're currently on the first line, move the label one line down
                 {
                     // This annotation needs a new line in the output.
@@ -374,7 +407,7 @@ fn render_source_line(&self,
                     } else {
                         0
                     };
-                    if overlaps(next, annotation, l) // Do not allow two labels to be in the same
+                    if (overlaps(next, annotation, l) // Do not allow two labels to be in the same
                                                      // line if they overlap including padding, to
                                                      // avoid situations like:
                                                      //
@@ -383,11 +416,18 @@ fn render_source_line(&self,
                                                      //      |      |
                                                      //      fn_spanx_span
                                                      //
-                        && !annotation.is_line()     // Do not add a new line if this annotation
-                        && !next.is_line()           // or the next are vertical line placeholders.
                         && annotation.has_label()    // Both labels must have some text, otherwise
-                        && next.has_label()          // they are not overlapping.
+                        && next.has_label())         // they are not overlapping.
+                                                     // Do not add a new line if this annotation
+                                                     // or the next are vertical line placeholders.
+                        || (annotation.takes_space() // If either this or the next annotation is
+                            && next.has_label())     // multiline start/end, move it to a new line
+                        || (annotation.has_label()   // so as not to overlap the orizontal lines.
+                            && next.takes_space())
+                        || (annotation.takes_space()
+                            && next.takes_space())
                     {
+                        // This annotation needs a new line in the output.
                         p += 1;
                         break;
                     }
@@ -397,6 +437,7 @@ fn render_source_line(&self,
                 line_len = p;
             }
         }
+
         if line_len != 0 {
             line_len += 1;
         }
@@ -480,7 +521,7 @@ fn render_source_line(&self,
             };
             let pos = pos + 1;
 
-            if pos > 1 && annotation.has_label() {
+            if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
                 for p in line_offset + 1..line_offset + pos + 1 {
                     buffer.putc(p,
                                 code_offset + annotation.start_col,
@@ -514,12 +555,12 @@ fn render_source_line(&self,
         // After this we will have:
         //
         // 2 |   fn foo() {
-        //   |  __________ starting here...
+        //   |  __________
         //   |      |
         //   |      something about `foo`
         // 3 |
         // 4 |   }
-        //   |  _  ...ending here: test
+        //   |  _  test
         for &(pos, annotation) in &annotations_position {
             let style = if annotation.is_primary {
                 Style::LabelPrimary
@@ -557,12 +598,12 @@ fn render_source_line(&self,
         // After this we will have:
         //
         // 2 |   fn foo() {
-        //   |  ____-_____^ starting here...
+        //   |  ____-_____^
         //   |      |
         //   |      something about `foo`
         // 3 |
         // 4 |   }
-        //   |  _^  ...ending here: test
+        //   |  _^  test
         for &(_, annotation) in &annotations_position {
             let (underline, style) = if annotation.is_primary {
                 ('^', Style::UnderlinePrimary)
index 9aa4682e1afcbfc2f8239803c64eaa0a6bb409d5..7401ead22089bcfaad6e6317004a2b20e2312695 100644 (file)
@@ -63,7 +63,7 @@ pub fn as_start(&self) -> Annotation {
             start_col: self.start_col,
             end_col: self.start_col + 1,
             is_primary: self.is_primary,
-            label: Some("starting here...".to_owned()),
+            label: None,
             annotation_type: AnnotationType::MultilineStart(self.depth)
         }
     }
@@ -73,10 +73,7 @@ pub fn as_end(&self) -> Annotation {
             start_col: self.end_col - 1,
             end_col: self.end_col,
             is_primary: self.is_primary,
-            label: match self.label {
-                Some(ref label) => Some(format!("...ending here: {}", label)),
-                None => Some("...ending here".to_owned()),
-            },
+            label: self.label.clone(),
             annotation_type: AnnotationType::MultilineEnd(self.depth)
         }
     }
@@ -106,9 +103,9 @@ pub enum AnnotationType {
     // Each of these corresponds to one part of the following diagram:
     //
     //     x |   foo(1 + bar(x,
-    //       |  _________^ starting here...           < MultilineStart
-    //     x | |             y),                      < MultilineLine
-    //       | |______________^ ...ending here: label < MultilineEnd
+    //       |  _________^              < MultilineStart
+    //     x | |             y),        < MultilineLine
+    //       | |______________^ label   < MultilineEnd
     //     x |       z);
     /// Annotation marking the first character of a fully shown multiline span
     MultilineStart(usize),
@@ -189,6 +186,15 @@ pub fn has_label(&self) -> bool {
             false
         }
     }
+
+    pub fn takes_space(&self) -> bool {
+        // Multiline annotations always have to keep vertical space.
+        match self.annotation_type {
+            AnnotationType::MultilineStart(_) |
+            AnnotationType::MultilineEnd(_) => true,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Debug)]
index 0ee9d4a42c7f81a26c15efdb0a37ab3eb5af6b45..1c69f3cff172a4321a49062bfcffcf3397e6c0fa 100644 (file)
@@ -1152,7 +1152,7 @@ fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
             let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
             for field in vdata.fields() {
                 let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id));
-                if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
+                if field_ty.needs_drop(ctx.tcx, param_env) {
                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
                                   field.span,
                                   "union contains a field with possibly non-trivial drop code, \
index a8def4bafd864b6e4203025c2082f233d9f87eb6..4871f60466dfd1b8062c534254da2aeea1b637e0 100644 (file)
@@ -268,4 +268,8 @@ fn main() {
     if target.contains("windows") {
         println!("cargo:rustc-link-lib=ole32");
     }
+    if target.contains("windows-gnu") {
+        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
+        println!("cargo:rustc-link-lib=static-nobundle=pthread");
+    }
 }
index f300bf16145a736c92f95768eb911ada60f24c3e..7c52ceae459cdbef0fbb55f7a759c849fb85ef22 100644 (file)
@@ -29,6 +29,7 @@
 #![feature(link_args)]
 #![feature(staged_api)]
 #![feature(rustc_private)]
+#![feature(static_nobundle)]
 
 extern crate libc;
 #[macro_use]
index a8ee999505e2074e2755a593316c05d8acd591ce..7bc0e8a512be02eb589a1d3036c494dd72b31e3a 100644 (file)
@@ -326,6 +326,7 @@ fn register_crate(&mut self,
             cnum_map: RefCell::new(cnum_map),
             cnum: cnum,
             codemap_import_info: RefCell::new(vec![]),
+            attribute_cache: RefCell::new([Vec::new(), Vec::new()]),
             dep_kind: Cell::new(dep_kind),
             source: cstore::CrateSource {
                 dylib: dylib,
index 17a6a706e0aaa1be559afd5d05406d9b0a1fc6bc..72ad1d75a5615761543ffdd61fd26b35a4fd2d38 100644 (file)
@@ -72,6 +72,7 @@ pub struct CrateMetadata {
     pub cnum_map: RefCell<CrateNumMap>,
     pub cnum: CrateNum,
     pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
+    pub attribute_cache: RefCell<[Vec<Option<Rc<[ast::Attribute]>>>; 2]>,
 
     pub root: schema::CrateRoot,
 
@@ -269,7 +270,7 @@ pub fn disambiguator(&self) -> Symbol {
     }
 
     pub fn is_staged_api(&self) -> bool {
-        for attr in self.get_item_attrs(CRATE_DEF_INDEX) {
+        for attr in self.get_item_attrs(CRATE_DEF_INDEX).iter() {
             if attr.path == "stable" || attr.path == "unstable" {
                 return true;
             }
index 3239dfb937b5e79bd170036a0d232252d159f450..9e6a45e7f8b7c68ddfed3850f607392154f616e4 100644 (file)
@@ -89,6 +89,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
     }
     associated_item => { cdata.get_associated_item(def_id.index) }
     impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
+    impl_polarity => { cdata.get_impl_polarity(def_id.index) }
     coerce_unsized_info => {
         cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
             bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
@@ -111,6 +112,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
     closure_kind => { cdata.closure_kind(def_id.index) }
     closure_type => { cdata.closure_ty(def_id.index, tcx) }
     inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
+    is_foreign_item => { cdata.is_foreign_item(def_id.index) }
 }
 
 impl CrateStore for cstore::CStore {
@@ -148,7 +150,7 @@ fn item_generics_cloned(&self, def: DefId) -> ty::Generics {
         self.get_crate_data(def.krate).get_generics(def.index)
     }
 
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
@@ -176,12 +178,6 @@ fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
         result
     }
 
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_impl_polarity(def.index)
-    }
-
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(impl_def));
         self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
@@ -405,7 +401,7 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
 
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index);
-        for attr in &attrs {
+        for attr in attrs.iter() {
             attr::mark_used(attr);
         }
 
@@ -418,25 +414,24 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
             ident: ast::Ident::with_empty_ctxt(name),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
-            attrs: attrs,
+            attrs: attrs.iter().cloned().collect(),
             node: ast::ItemKind::MacroDef(body.into()),
             vis: ast::Visibility::Inherited,
         })
     }
 
-    fn maybe_get_item_body<'a, 'tcx>(&self,
-                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     def_id: DefId)
-                                     -> Option<&'tcx hir::Body>
-    {
+    fn item_body<'a, 'tcx>(&self,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx hir::Body {
         if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
-            return Some(cached);
+            return cached;
         }
 
         self.dep_graph.read(DepNode::MetaData(def_id));
-        debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
+        debug!("item_body({}): inlining item", tcx.item_path_str(def_id));
 
-        self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index)
+        self.get_crate_data(def_id.krate).item_body(tcx, def_id.index)
     }
 
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
index fac6079529e30187af8c4830be5d44876fbaffab..a9eae5281b241fa3ede78cdb699560f798ae501a 100644 (file)
@@ -31,6 +31,7 @@
 use std::collections::BTreeMap;
 use std::io;
 use std::mem;
+use std::rc::Rc;
 use std::str;
 use std::u32;
 
@@ -749,16 +750,15 @@ pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
         }
     }
 
-    pub fn maybe_get_item_body(&self,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               id: DefIndex)
-                               -> Option<&'tcx hir::Body> {
-        if self.is_proc_macro(id) { return None; }
-        self.entry(id).ast.map(|ast| {
-            let def_id = self.local_def_id(id);
-            let body = ast.decode(self).body.decode(self);
-            tcx.hir.intern_inlined_body(def_id, body)
-        })
+    pub fn item_body(&self,
+                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     id: DefIndex)
+                     -> &'tcx hir::Body {
+        assert!(!self.is_proc_macro(id));
+        let ast = self.entry(id).ast.unwrap();
+        let def_id = self.local_def_id(id);
+        let body = ast.decode(self).body.decode(self);
+        tcx.hir.intern_inlined_body(def_id, body)
     }
 
     pub fn item_body_tables(&self,
@@ -859,10 +859,18 @@ pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
         }
     }
 
-    pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
+    pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> {
+        let (node_as, node_index) =
+            (node_id.address_space().index(), node_id.as_array_index());
         if self.is_proc_macro(node_id) {
-            return Vec::new();
+            return Rc::new([]);
+        }
+
+        if let Some(&Some(ref val)) =
+            self.attribute_cache.borrow()[node_as].get(node_index) {
+            return val.clone();
         }
+
         // The attributes for a tuple struct are attached to the definition, not the ctor;
         // we assume that someone passing in a tuple struct ctor is actually wanting to
         // look at the definition
@@ -871,7 +879,13 @@ pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
         if def_key.disambiguated_data.data == DefPathData::StructCtor {
             item = self.entry(def_key.parent.unwrap());
         }
-        self.get_attributes(&item)
+        let result = Rc::__from_array(self.get_attributes(&item).into_boxed_slice());
+        let vec_ = &mut self.attribute_cache.borrow_mut()[node_as];
+        if vec_.len() < node_index + 1 {
+            vec_.resize(node_index + 1, None);
+        }
+        vec_[node_index] = Some(result.clone());
+        result
     }
 
     pub fn get_struct_field_names(&self, id: DefIndex) -> Vec<ast::Name> {
index 5fece4d6a5d2387aae043ceb46cd070b98ea66e5..0833342927fec9dbbb31bab1164aa70a44080b58 100644 (file)
@@ -280,7 +280,7 @@ pub fn perform_test(&mut self,
                     assert!(ty.is_slice());
 
                     let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
-                    let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty);
+                    let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
                     let array = self.literal_operand(test.span, array_ref, Literal::Value {
                         value: value.clone()
                     });
index b7de50efe34424bb14e621b60a6d1609825638b1..736c076ea15446cb4b510cafb72e434290df6fef 100644 (file)
@@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let c = &cx.tcx.hir.body(count).value;
             let def_id = cx.tcx.hir.body_owner_def_id(count);
-            let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) {
+            let substs = Substs::empty();
+            let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
index 5f9fb8e1b120f040c57486f2cf285e0ed1b512e7..db9da2a280b94cc70af7e43645fef9e0e1b247bf 100644 (file)
@@ -168,7 +168,7 @@ pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
                   type with inference types/regions",
                  ty);
         });
-        self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment)
+        ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment)
     }
 
     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
index 4d70540a7c688166b58f1bb265a49decd31cb5dc..7f7377e5ffe3f78a2d9c4cf7f7f161dcef2bb6b8 100644 (file)
@@ -308,10 +308,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         Adjustment::Deref => Operand::Consume(rcvr_l.deref()),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
-            let re_erased = tcx.mk_region(ty::ReErased);
             let ref_rcvr = local_decls.push(temp_decl(
                 Mutability::Not,
-                tcx.mk_ref(re_erased, ty::TypeAndMut {
+                tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
                     ty: sig.inputs()[0],
                     mutbl: hir::Mutability::MutMutable
                 }),
@@ -321,7 +320,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 source_info: source_info,
                 kind: StatementKind::Assign(
                     Lvalue::Local(ref_rcvr),
-                    Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l)
+                    Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
                 )
             });
             Operand::Consume(Lvalue::Local(ref_rcvr))
index 0f869e7ed02ffef25565302aeec721879061ac8d..5cc5cf297936d3606a90a5f62bd4e7155608c860 100644 (file)
@@ -13,7 +13,7 @@
 //! care erasing regions all over the place.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts};
+use rustc::ty::{Ty, TyCtxt, ClosureSubsts};
 use rustc::mir::*;
 use rustc::mir::visit::MutVisitor;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
@@ -43,7 +43,7 @@ fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
         match *rvalue {
             Rvalue::Ref(ref mut r, _, _) => {
-                *r = self.tcx.mk_region(ReErased);
+                *r = self.tcx.types.re_erased;
             }
             Rvalue::Use(..) |
             Rvalue::Repeat(..) |
index ac2bdaad24f766a397d2f5c53da0b3bc0bf877f1..45bdff9195c4f10924987830f7f12e6810f778f6 100644 (file)
@@ -357,7 +357,7 @@ fn should_inline(&self, callsite: CallSite<'tcx>,
                     // a regular goto.
                     let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
                     let ty = ty.to_ty(tcx);
-                    if tcx.type_needs_drop_given_env(ty, &param_env) {
+                    if ty.needs_drop(tcx, &param_env) {
                         cost += CALL_PENALTY;
                         if let Some(unwind) = unwind {
                             work_list.push(unwind);
@@ -497,7 +497,7 @@ fn dest_needs_borrow(lval: &Lvalue) -> bool {
                 let dest = if dest_needs_borrow(&destination.0) {
                     debug!("Creating temp for return destination");
                     let dest = Rvalue::Ref(
-                        self.tcx.mk_region(ty::ReErased),
+                        self.tcx.types.re_erased,
                         BorrowKind::Mut,
                         destination.0);
 
@@ -582,7 +582,7 @@ fn dest_needs_borrow(lval: &Lvalue) -> bool {
     fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>,
                          callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> {
         let arg = Rvalue::Ref(
-            self.tcx.mk_region(ty::ReErased),
+            self.tcx.types.re_erased,
             BorrowKind::Mut,
             arg.deref());
 
index 1313b24fa74f5eecc5311586c9f12e10f406b51c..526c1488ab480e96fe6873c985548f3cb7d8b610 100644 (file)
@@ -80,10 +80,10 @@ impl<'a, 'tcx> Qualif {
     fn restrict(&mut self, ty: Ty<'tcx>,
                 tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 param_env: &ty::ParameterEnvironment<'tcx>) {
-        if !ty.type_contents(tcx).interior_unsafe() {
+        if ty.is_freeze(tcx, param_env, DUMMY_SP) {
             *self = *self - Qualif::MUTABLE_INTERIOR;
         }
-        if !tcx.type_needs_drop_given_env(ty, param_env) {
+        if !ty.needs_drop(tcx, param_env) {
             *self = *self - Qualif::NEEDS_DROP;
         }
     }
index 0a8f147b2141055ac0cec37a56a0e5659bbd421d..ef7990653ba982cc8de8319fad9e9401d1729535 100644 (file)
@@ -124,6 +124,8 @@ pub fn simplify(mut self) {
                     self.collapse_goto_chain(successor, &mut changed);
                 }
 
+                changed |= self.simplify_unwind(&mut terminator);
+
                 let mut new_stmts = vec![];
                 let mut inner_changed = true;
                 while inner_changed {
@@ -238,6 +240,38 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
         true
     }
 
+    // turn an unwind branch to a resume block into a None
+    fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
+        let unwind = match terminator.kind {
+            TerminatorKind::Drop { ref mut unwind, .. } |
+            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
+            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
+            TerminatorKind::Assert { cleanup: ref mut unwind, .. } =>
+                unwind,
+            _ => return false
+        };
+
+        if let &mut Some(unwind_block) = unwind {
+            let is_resume_block = match self.basic_blocks[unwind_block] {
+                BasicBlockData {
+                    ref statements,
+                    terminator: Some(Terminator {
+                        kind: TerminatorKind::Resume, ..
+                    }), ..
+                } if statements.is_empty() => true,
+                _ => false
+            };
+            if is_resume_block {
+                debug!("simplifying unwind to {:?} from {:?}",
+                       unwind_block, terminator.source_info);
+                *unwind = None;
+            }
+            return is_resume_block;
+        }
+
+        false
+    }
+
     fn strip_nops(&mut self) {
         for blk in self.basic_blocks.iter_mut() {
             blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
index 04a1fc891cf1e582e2ef50d2b4271bf8df16bd6c..9d7c7ec63cfc57afbc32eccfa5dfb5cee46185c2 100644 (file)
@@ -277,8 +277,7 @@ fn drop_ladder<'a>(&mut self,
 
         let mut fields = fields;
         fields.retain(|&(ref lvalue, _)| {
-            self.tcx().type_needs_drop_given_env(
-                self.lvalue_ty(lvalue), self.elaborator.param_env())
+            self.lvalue_ty(lvalue).needs_drop(self.tcx(), self.elaborator.param_env())
         });
 
         debug!("drop_ladder - fields needing drop: {:?}", fields);
@@ -507,8 +506,7 @@ fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Option<Basi
         let ty = self.lvalue_ty(self.lvalue);
         let substs = tcx.mk_substs(iter::once(Kind::from(ty)));
 
-        let re_erased = tcx.mk_region(ty::ReErased);
-        let ref_ty = tcx.mk_ref(re_erased, ty::TypeAndMut {
+        let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
             ty: ty,
             mutbl: hir::Mutability::MutMutable
         });
@@ -520,7 +518,7 @@ fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Option<Basi
                 source_info: self.source_info,
                 kind: StatementKind::Assign(
                     Lvalue::Local(ref_lvalue),
-                    Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone())
+                    Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone())
                 )
             }],
             terminator: Some(Terminator {
index 2c4439f80a23906e250356a4a0d86729d90adfe6..fdb67522133781f74b3c2430ab58bc3aec917006 100644 (file)
@@ -46,7 +46,7 @@
 
 use rustc::hir::{self, PatKind, RangeEnd};
 use syntax::ast;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
 use std::collections::hash_map::Entry;
@@ -85,11 +85,11 @@ fn check_const_eval(&self, expr: &'gcx hir::Expr) {
 
     // Adds the worst effect out of all the values of one type.
     fn add_type(&mut self, ty: Ty<'gcx>) {
-        if ty.type_contents(self.tcx).interior_unsafe() {
+        if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) {
             self.promotable = false;
         }
 
-        if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
+        if ty.needs_drop(self.tcx, &self.param_env) {
             self.promotable = false;
         }
     }
index 92f7e48b6be4853f23321529f98156d4be2cfe4d..f7155f219a828a78b1dbc4929b0dd46cf0ab1ed0 100644 (file)
@@ -13,8 +13,8 @@
 #![crate_type = "dylib"]
 #![crate_type = "rlib"]
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
-      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
-      html_root_url = "https://doc.rust-lang.org/nightly/")]
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![deny(warnings)]
 
 #![feature(rustc_diagnostic_macros)]
@@ -30,7 +30,6 @@
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::DeepVisitor;
-use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
 use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
@@ -415,52 +414,32 @@ fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-/// The privacy visitor, where privacy checks take place (violations reported)
-////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+/// Name privacy visitor, checks privacy and reports violations.
+/// Most of name privacy checks are performed during the main resolution phase,
+/// or later in type checking when field accesses and associated items are resolved.
+/// This pass performs remaining checks for fields in struct expressions and patterns.
+//////////////////////////////////////////////////////////////////////////////////////
 
-struct PrivacyVisitor<'a, 'tcx: 'a> {
+struct NamePrivacyVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    curitem: DefId,
-    in_foreign: bool,
     tables: &'a ty::TypeckTables<'tcx>,
+    current_item: DefId,
 }
 
-impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
-    fn item_is_accessible(&self, did: DefId) -> bool {
-        match self.tcx.hir.as_local_node_id(did) {
-            Some(node_id) =>
-                ty::Visibility::from_hir(&self.tcx.hir.expect_item(node_id).vis, node_id, self.tcx),
-            None => self.tcx.sess.cstore.visibility(did),
-        }.is_accessible_from(self.curitem, self.tcx)
-    }
-
-    // Checks that a field is in scope.
+impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
+    // Checks that a field is accessible.
     fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) {
-        if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, self.tcx) {
+        if !def.is_enum() && !field.vis.is_accessible_from(self.current_item, self.tcx) {
             struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
-                      field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
+                             field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
                 .span_label(span, &format!("field `{}` is private", field.name))
                 .emit();
         }
     }
-
-    // Checks that a method is in scope.
-    fn check_method(&mut self, span: Span, method_def_id: DefId) {
-        match self.tcx.associated_item(method_def_id).container {
-            // Trait methods are always all public. The only controlling factor
-            // is whether the trait itself is accessible or not.
-            ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => {
-                let msg = format!("source trait `{}` is private",
-                                  self.tcx.item_path_str(trait_def_id));
-                self.tcx.sess.span_err(span, &msg);
-            }
-            _ => {}
-        }
-    }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
@@ -468,44 +447,36 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_tables = self.tables;
-        self.tables = self.tcx.body_tables(body);
+        let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
         let body = self.tcx.hir.body(body);
         self.visit_body(body);
-        self.tables = old_tables;
+        self.tables = orig_tables;
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        let orig_curitem = replace(&mut self.curitem, self.tcx.hir.local_def_id(item.id));
+        let orig_current_item = replace(&mut self.current_item, self.tcx.hir.local_def_id(item.id));
         intravisit::walk_item(self, item);
-        self.curitem = orig_curitem;
+        self.current_item = orig_current_item;
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
-            hir::ExprMethodCall(..) => {
-                let method_call = ty::MethodCall::expr(expr.id);
-                let method = self.tables.method_map[&method_call];
-                self.check_method(expr.span, method.def_id);
-            }
-            hir::ExprStruct(ref qpath, ref expr_fields, _) => {
+            hir::ExprStruct(ref qpath, ref fields, ref base) => {
                 let def = self.tables.qpath_def(qpath, expr.id);
                 let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(def);
-                // RFC 736: ensure all unmentioned fields are visible.
-                // Rather than computing the set of unmentioned fields
-                // (i.e. `all_fields - fields`), just check them all,
-                // unless the ADT is a union, then unmentioned fields
-                // are not checked.
-                if adt.is_union() {
-                    for expr_field in expr_fields {
-                        self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
+                if let Some(ref base) = *base {
+                    // If the expression uses FRU we need to make sure all the unmentioned fields
+                    // are checked for privacy (RFC 736). Rather than computing the set of
+                    // unmentioned fields, just check them all.
+                    for variant_field in &variant.fields {
+                        let field = fields.iter().find(|f| f.name.node == variant_field.name);
+                        let span = if let Some(f) = field { f.span } else { base.span };
+                        self.check_field(span, adt, variant_field);
                     }
                 } else {
-                    for field in &variant.fields {
-                        let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
-                        let span = if let Some(f) = expr_field { f.span } else { expr.span };
-                        self.check_field(span, adt, field);
+                    for field in fields {
+                        self.check_field(field.span, adt, variant.field_named(field.name.node));
                     }
                 }
             }
@@ -515,47 +486,20 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         intravisit::walk_expr(self, expr);
     }
 
-    fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
-        // Foreign functions do not have their patterns mapped in the def_map,
-        // and there's nothing really relevant there anyway, so don't bother
-        // checking privacy. If you can name the type then you can pass it to an
-        // external C function anyway.
-        if self.in_foreign { return }
-
-        match pattern.node {
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
+        match pat.node {
             PatKind::Struct(ref qpath, ref fields, _) => {
-                let def = self.tables.qpath_def(qpath, pattern.id);
-                let adt = self.tables.pat_ty(pattern).ty_adt_def().unwrap();
+                let def = self.tables.qpath_def(qpath, pat.id);
+                let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(def);
                 for field in fields {
                     self.check_field(field.span, adt, variant.field_named(field.node.name));
                 }
             }
-            PatKind::TupleStruct(_, ref fields, ddpos) => {
-                match self.tables.pat_ty(pattern).sty {
-                    // enum fields have no privacy at this time
-                    ty::TyAdt(def, _) if !def.is_enum() => {
-                        let expected_len = def.struct_variant().fields.len();
-                        for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) {
-                            if let PatKind::Wild = field.node {
-                                continue
-                            }
-                            self.check_field(field.span, def, &def.struct_variant().fields[i]);
-                        }
-                    }
-                    _ => {}
-                }
-            }
             _ => {}
         }
 
-        intravisit::walk_pat(self, pattern);
-    }
-
-    fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
-        self.in_foreign = true;
-        intravisit::walk_foreign_item(self, fi);
-        self.in_foreign = false;
+        intravisit::walk_pat(self, pat);
     }
 }
 
@@ -1233,17 +1177,14 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let krate = tcx.hir.krate();
 
-    // Use the parent map to check the privacy of everything
-    let mut visitor = PrivacyVisitor {
-        curitem: DefId::local(CRATE_DEF_INDEX),
-        in_foreign: false,
+    // Check privacy of names not checked in previous compilation stages.
+    let mut visitor = NamePrivacyVisitor {
         tcx: tcx,
         tables: &ty::TypeckTables::empty(),
+        current_item: DefId::local(CRATE_DEF_INDEX),
     };
     intravisit::walk_crate(&mut visitor, krate);
 
-    tcx.sess.abort_if_errors();
-
     // Build up a set of all exported items in the AST. This is a set of all
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
index c4fdc46d030c9e163d2b0a9d8d2f4637f8f5ef58..998e392b1f9078ac78dc68e4746666e8d0309e2e 100644 (file)
@@ -553,7 +553,7 @@ pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) {
                 //   bitcasting to the struct type yields invalid cast errors.
 
                 // We instead thus allocate some scratch space...
-                let llscratch = bcx.alloca(ty, "abi_cast");
+                let llscratch = bcx.alloca(ty, "abi_cast", None);
                 base::Lifetime::Start.call(bcx, llscratch);
 
                 // ...where we first store the value...
@@ -746,13 +746,13 @@ pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>,
                 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
                 // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
                 // on memory dependencies rather than pointer equality
-                let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
+                let is_freeze = ccx.shared().type_is_freeze(mt.ty);
 
-                if mt.mutbl != hir::MutMutable && !interior_unsafe {
+                if mt.mutbl != hir::MutMutable && is_freeze {
                     arg.attrs.set(ArgAttribute::NoAlias);
                 }
 
-                if mt.mutbl == hir::MutImmutable && !interior_unsafe {
+                if mt.mutbl == hir::MutImmutable && is_freeze {
                     arg.attrs.set(ArgAttribute::ReadOnly);
                 }
 
index 87ca410dece0dcee116b43653044c586653712f5..d1c1dd7436a5ba5fae0ea61492cb6ddf22cc4bb2 100644 (file)
@@ -90,12 +90,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
 /// and fill in the actual contents in a second pass to prevent
 /// unbounded recursion; see also the comments in `trans::type_of`.
 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
-    generic_type_of(cx, t, None, false, false)
+    generic_type_of(cx, t, None)
 }
 
 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)
+    generic_type_of(cx, t, Some(name))
 }
 
 pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
@@ -114,7 +114,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 _ => unreachable!()
             };
             let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
-            llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
+            llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant),
                                  packed)
         },
         _ => bug!("This function cannot handle {} with layout {:#?}", t, l)
@@ -123,12 +123,9 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                              t: Ty<'tcx>,
-                             name: Option<&str>,
-                             sizing: bool,
-                             dst: bool) -> Type {
+                             name: Option<&str>) -> Type {
     let l = cx.layout_of(t);
-    debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {} dst: {}",
-           t, name, sizing, dst);
+    debug!("adt::generic_type_of t: {:?} name: {:?}", t, name);
     match *l {
         layout::CEnum { discr, .. } => Type::from_integer(cx, discr),
         layout::RawNullablePointer { nndiscr, .. } => {
@@ -148,11 +145,10 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, nndiscr as usize, false);
             match name {
                 None => {
-                    Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
+                    Type::struct_(cx, &struct_llfields(cx, &fields, nonnull),
                                   nonnull.packed)
                 }
                 Some(name) => {
-                    assert_eq!(sizing, false);
                     Type::named_struct(cx, name)
                 }
             }
@@ -163,13 +159,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, 0, true);
             match name {
                 None => {
-                    let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
+                    let fields = struct_llfields(cx, &fields, &variant);
                     Type::struct_(cx, &fields, variant.packed)
                 }
                 Some(name) => {
                     // Hypothesis: named_struct's can never need a
                     // drop flag. (... needs validation.)
-                    assert_eq!(sizing, false);
                     Type::named_struct(cx, name)
                 }
             }
@@ -190,7 +185,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        layout::General { discr, size, align, .. } => {
+        layout::General { discr, size, align, primitive_align, .. } => {
             // We need a representation that has:
             // * The alignment of the most-aligned field
             // * The size of the largest variant (rounded up to that alignment)
@@ -203,14 +198,15 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             // of the size.
             let size = size.bytes();
             let align = align.abi();
+            let primitive_align = primitive_align.abi();
             assert!(align <= std::u32::MAX as u64);
             let discr_ty = Type::from_integer(cx, discr);
             let discr_size = discr.size().bytes();
             let padded_discr_size = roundup(discr_size, align as u32);
             let variant_part_size = size-padded_discr_size;
-            let variant_fill = union_fill(cx, variant_part_size, align);
+            let variant_fill = union_fill(cx, variant_part_size, primitive_align);
 
-            assert_eq!(machine::llalign_of_min(cx, variant_fill), align as u32);
+            assert_eq!(machine::llalign_of_min(cx, variant_fill), primitive_align as u32);
             assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
             let fields: Vec<Type> =
                 [discr_ty,
@@ -245,15 +241,60 @@ 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> {
-    let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
-    if sizing {
-        bug!()
+// Double index to account for padding (FieldPath already uses `Struct::memory_index`)
+fn struct_llfields_path(discrfield: &layout::FieldPath) -> Vec<usize> {
+    discrfield.iter().map(|&i| (i as usize) << 1).collect::<Vec<_>>()
+}
+
+
+// Lookup `Struct::memory_index` and double it to account for padding
+pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize {
+    (variant.memory_index[index] as usize) << 1
+}
+
+
+pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, field_tys: &Vec<Ty<'tcx>>,
+                             variant: &layout::Struct) -> Vec<Type> {
+    debug!("struct_llfields: variant: {:?}", variant);
+    let mut first_field = true;
+    let mut min_offset = 0;
+    let mut result: Vec<Type> = Vec::with_capacity(field_tys.len() * 2);
+    let field_iter = variant.field_index_by_increasing_offset().map(|i| {
+        (i, field_tys[i as usize], variant.offsets[i as usize].bytes()) });
+    for (index, ty, target_offset) in field_iter {
+        if first_field {
+            debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}",
+                index, ty, min_offset, target_offset);
+            first_field = false;
+        } else {
+            assert!(target_offset >= min_offset);
+            let padding_bytes = if variant.packed { 0 } else { target_offset - min_offset };
+            result.push(Type::array(&Type::i8(cx), padding_bytes));
+            debug!("struct_llfields: {} ty: {} pad_bytes: {} min_offset: {} target_offset: {}",
+                index, ty, padding_bytes, min_offset, target_offset);
+        }
+        let llty = type_of::in_memory_type_of(cx, ty);
+        result.push(llty);
+        let layout = cx.layout_of(ty);
+        let target_size = layout.size(&cx.tcx().data_layout).bytes();
+        min_offset = target_offset + target_size;
+    }
+    if variant.sized && !field_tys.is_empty() {
+        if variant.stride().bytes() < min_offset {
+            bug!("variant: {:?} stride: {} min_offset: {}", variant, variant.stride().bytes(),
+            min_offset);
+        }
+        let padding_bytes = variant.stride().bytes() - min_offset;
+        debug!("struct_llfields: pad_bytes: {} min_offset: {} min_size: {} stride: {}\n",
+               padding_bytes, min_offset, variant.min_size.bytes(), variant.stride().bytes());
+        result.push(Type::array(&Type::i8(cx), padding_bytes));
+        assert!(result.len() == (field_tys.len() * 2));
     } else {
-        fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
+        debug!("struct_llfields: min_offset: {} min_size: {} stride: {}\n",
+               min_offset, variant.min_size.bytes(), variant.stride().bytes());
     }
+
+    result
 }
 
 pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
@@ -309,8 +350,8 @@ fn struct_wrapped_nullable_bitdiscr(
     scrutinee: ValueRef,
     alignment: Alignment,
 ) -> ValueRef {
-    let llptrptr = bcx.gepi(scrutinee,
-        &discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>());
+    let path = struct_llfields_path(discrfield);
+    let llptrptr = bcx.gepi(scrutinee, &path);
     let llptr = bcx.load(llptrptr, alignment.to_align());
     let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
     bcx.icmp(cmp, llptr, C_null(val_ty(llptr)))
@@ -380,7 +421,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
                     let align = C_i32(bcx.ccx, nonnull.align.abi() as i32);
                     base::call_memset(bcx, llptr, fill_byte, size, align, false);
                 } else {
-                    let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
+                    let path = struct_llfields_path(discrfield);
                     let llptrptr = bcx.gepi(val, &path);
                     let llptrty = val_ty(llptrptr).element_type();
                     bcx.store(C_null(llptrty), llptrptr, None);
index 5d6717272fdf3d000fdea7c56f5a14815f081cc1..221c52141a8323de0193f3d2a926599df704a5b9 100644 (file)
@@ -53,7 +53,7 @@ pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 scx.tcx().hir.local_def_id(node_id)
             })
             .map(|def_id| {
-                let name = symbol_for_def_id(scx, def_id, symbol_map);
+                let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map);
                 let export_level = export_level(scx, def_id);
                 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
                 (name, export_level)
@@ -108,7 +108,7 @@ pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 .exported_symbols(cnum)
                 .iter()
                 .map(|&def_id| {
-                    let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx);
+                    let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx());
                     let export_level = if special_runtime_crate {
                         // We can probably do better here by just ensuring that
                         // it has hidden visibility rather than public
@@ -214,21 +214,21 @@ pub fn is_below_threshold(level: SymbolExportLevel,
     }
 }
 
-fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                def_id: DefId,
                                symbol_map: &SymbolMap<'tcx>)
                                -> String {
     // Just try to look things up in the symbol map. If nothing's there, we
     // recompute.
-    if let Some(node_id) = scx.tcx().hir.as_local_node_id(def_id) {
+    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
             return sym.to_owned();
         }
     }
 
-    let instance = Instance::mono(scx.tcx(), def_id);
+    let instance = Instance::mono(tcx, def_id);
 
     symbol_map.get(TransItem::Fn(instance))
               .map(str::to_owned)
-              .unwrap_or_else(|| symbol_name(instance, scx))
+              .unwrap_or_else(|| symbol_name(instance, tcx))
 }
index 8facbd6cc278373299585b0dd64dd5904fcc62f8..f21864764ddf1f828b428414ab2449d0e028e7c3 100644 (file)
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use common::SharedCrateContext;
 use monomorphize::Instance;
 
 use rustc::middle::weak_lang_items;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::fold::TypeVisitor;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::subst::Substs;
 use rustc::util::common::record_time;
 
 use syntax::attr;
-use syntax::symbol::{Symbol, InternedString};
 
-fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+use std::fmt::Write;
+
+fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                              // the DefId of the item this name is for
                              def_id: Option<DefId>,
@@ -130,8 +130,6 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                              -> String {
     debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
 
-    let tcx = scx.tcx();
-
     let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
 
     record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
@@ -157,8 +155,8 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             // in case the same instances is emitted in two crates of the same
             // project.
             if substs.types().next().is_some() {
-                hasher.hash(scx.tcx().crate_name.as_str());
-                hasher.hash(scx.sess().local_crate_disambiguator().as_str());
+                hasher.hash(tcx.crate_name.as_str());
+                hasher.hash(tcx.sess.local_crate_disambiguator().as_str());
             }
         }
     });
@@ -168,37 +166,37 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 }
 
 pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
-                             scx: &SharedCrateContext<'a, 'tcx>) -> String {
+                             tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
     let def_id = instance.def_id();
     let substs = instance.substs;
 
     debug!("symbol_name(def_id={:?}, substs={:?})",
            def_id, substs);
 
-    let node_id = scx.tcx().hir.as_local_node_id(def_id);
+    let node_id = tcx.hir.as_local_node_id(def_id);
 
     if let Some(id) = node_id {
-        if scx.sess().plugin_registrar_fn.get() == Some(id) {
+        if tcx.sess.plugin_registrar_fn.get() == Some(id) {
             let idx = def_id.index;
-            let disambiguator = scx.sess().local_crate_disambiguator();
-            return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx);
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx);
         }
-        if scx.sess().derive_registrar_fn.get() == Some(id) {
+        if tcx.sess.derive_registrar_fn.get() == Some(id) {
             let idx = def_id.index;
-            let disambiguator = scx.sess().local_crate_disambiguator();
-            return scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
         }
     }
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let attrs = scx.tcx().get_attrs(def_id);
+    let attrs = tcx.get_attrs(def_id);
     let is_foreign = if let Some(id) = node_id {
-        match scx.tcx().hir.get(id) {
+        match tcx.hir.get(id) {
             hir_map::NodeForeignItem(_) => true,
             _ => false
         }
     } else {
-        scx.sess().cstore.is_foreign_item(def_id)
+        tcx.sess.cstore.is_foreign_item(def_id)
     };
 
     if let Some(name) = weak_lang_items::link_name(&attrs) {
@@ -210,17 +208,17 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
             return name.to_string();
         }
         // Don't mangle foreign items.
-        return scx.tcx().item_name(def_id).as_str().to_string();
+        return tcx.item_name(def_id).as_str().to_string();
     }
 
-    if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) {
+    if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) {
         // Use provided name
         return name.to_string();
     }
 
     if attr::contains_name(&attrs, "no_mangle") {
         // Don't mangle
-        return scx.tcx().item_name(def_id).as_str().to_string();
+        return tcx.item_name(def_id).as_str().to_string();
     }
 
     // We want to compute the "type" of this item. Unfortunately, some
@@ -230,11 +228,11 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
     let mut ty_def_id = def_id;
     let instance_ty;
     loop {
-        let key = scx.tcx().def_key(ty_def_id);
+        let key = tcx.def_key(ty_def_id);
         match key.disambiguated_data.data {
             DefPathData::TypeNs(_) |
             DefPathData::ValueNs(_) => {
-                instance_ty = scx.tcx().item_type(ty_def_id);
+                instance_ty = tcx.item_type(ty_def_id);
                 break;
             }
             _ => {
@@ -251,23 +249,51 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
 
     // Erase regions because they may not be deterministic when hashed
     // and should not matter anyhow.
-    let instance_ty = scx.tcx().erase_regions(&instance_ty);
-
-    let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs));
+    let instance_ty = tcx.erase_regions(&instance_ty);
 
-    let mut buffer = SymbolPathBuffer {
-        names: Vec::new()
-    };
+    let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs));
 
+    let mut buffer = SymbolPathBuffer::new();
     item_path::with_forced_absolute_paths(|| {
-        scx.tcx().push_item_path(&mut buffer, def_id);
+        tcx.push_item_path(&mut buffer, def_id);
     });
-
-    mangle(buffer.names.into_iter(), &hash)
+    buffer.finish(&hash)
 }
 
+// Follow C++ namespace-mangling style, see
+// http://en.wikipedia.org/wiki/Name_mangling for more info.
+//
+// It turns out that on macOS you can actually have arbitrary symbols in
+// function names (at least when given to LLVM), but this is not possible
+// when using unix's linker. Perhaps one day when we just use a linker from LLVM
+// we won't need to do this name mangling. The problem with name mangling is
+// that it seriously limits the available characters. For example we can't
+// have things like &T in symbol names when one would theoretically
+// want them for things like impls of traits on that type.
+//
+// To be able to work on all platforms and get *some* reasonable output, we
+// use C++ name-mangling.
 struct SymbolPathBuffer {
-    names: Vec<InternedString>,
+    result: String,
+    temp_buf: String
+}
+
+impl SymbolPathBuffer {
+    fn new() -> Self {
+        let mut result = SymbolPathBuffer {
+            result: String::with_capacity(64),
+            temp_buf: String::with_capacity(16)
+        };
+        result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
+        result
+    }
+
+    fn finish(mut self, hash: &str) -> String {
+        // end name-sequence
+        self.push(hash);
+        self.result.push('E');
+        self.result
+    }
 }
 
 impl ItemPathBuffer for SymbolPathBuffer {
@@ -277,24 +303,32 @@ fn root_mode(&self) -> &RootMode {
     }
 
     fn push(&mut self, text: &str) {
-        self.names.push(Symbol::intern(text).as_str());
+        self.temp_buf.clear();
+        let need_underscore = sanitize(&mut self.temp_buf, text);
+        let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
+        if need_underscore {
+            self.result.push('_');
+        }
+        self.result.push_str(&self.temp_buf);
     }
 }
 
-pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     t: Ty<'tcx>,
                                                     prefix: &str)
                                                     -> String {
-    let hash = get_symbol_hash(scx, None, t, None);
-    let path = [Symbol::intern(prefix).as_str()];
-    mangle(path.iter().cloned(), &hash)
+    let hash = get_symbol_hash(tcx, None, t, None);
+    let mut buffer = SymbolPathBuffer::new();
+    buffer.push(prefix);
+    buffer.finish(&hash)
 }
 
 // Name sanitation. LLVM will happily accept identifiers with weird names, but
 // gas doesn't!
 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
-pub fn sanitize(s: &str) -> String {
-    let mut result = String::new();
+//
+// returns true if an underscore must be added at the start
+pub fn sanitize(result: &mut String, s: &str) -> bool {
     for c in s.chars() {
         match c {
             // Escape these with $ sequences
@@ -331,44 +365,7 @@ pub fn sanitize(s: &str) -> String {
     }
 
     // Underscore-qualify anything that didn't start as an ident.
-    if !result.is_empty() &&
+    !result.is_empty() &&
         result.as_bytes()[0] != '_' as u8 &&
-        ! (result.as_bytes()[0] as char).is_xid_start() {
-        return format!("_{}", result);
-    }
-
-    return result;
-}
-
-fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
-    // Follow C++ namespace-mangling style, see
-    // http://en.wikipedia.org/wiki/Name_mangling for more info.
-    //
-    // It turns out that on macOS you can actually have arbitrary symbols in
-    // function names (at least when given to LLVM), but this is not possible
-    // when using unix's linker. Perhaps one day when we just use a linker from LLVM
-    // we won't need to do this name mangling. The problem with name mangling is
-    // that it seriously limits the available characters. For example we can't
-    // have things like &T in symbol names when one would theoretically
-    // want them for things like impls of traits on that type.
-    //
-    // To be able to work on all platforms and get *some* reasonable output, we
-    // use C++ name-mangling.
-
-    let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
-
-    fn push(n: &mut String, s: &str) {
-        let sani = sanitize(s);
-        n.push_str(&format!("{}{}", sani.len(), sani));
-    }
-
-    // First, connect each component with <len, name> pairs.
-    for data in path {
-        push(&mut n, &data);
-    }
-
-    push(&mut n, hash);
-
-    n.push('E'); // End name-sequence.
-    n
+        ! (result.as_bytes()[0] as char).is_xid_start()
 }
index cb8022efedb84146a166b0682771dc539f77f574..ba119bd9ef069b01be558592183d795bacca7e73 100644 (file)
@@ -65,6 +65,7 @@
 use mir;
 use monomorphize::{self, Instance};
 use partitioning::{self, PartitioningStrategy, CodegenUnit};
+use symbol_cache::SymbolCache;
 use symbol_map::SymbolMap;
 use symbol_names_test;
 use trans_item::{TransItem, DefPathBasedNames};
@@ -75,7 +76,6 @@
 
 use libc::c_uint;
 use std::ffi::{CStr, CString};
-use std::rc::Rc;
 use std::str;
 use std::i32;
 use syntax_pos::Span;
@@ -802,6 +802,7 @@ enum MetadataKind {
 /// in any other compilation unit.  Give these symbols internal linkage.
 fn internalize_symbols<'a, 'tcx>(sess: &Session,
                                  scx: &SharedCrateContext<'a, 'tcx>,
+                                 translation_items: &FxHashSet<TransItem<'tcx>>,
                                  llvm_modules: &[ModuleLlvm],
                                  symbol_map: &SymbolMap<'tcx>,
                                  exported_symbols: &ExportedSymbols) {
@@ -854,7 +855,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
             let mut locally_defined_symbols = FxHashSet();
             let mut linkage_fixed_explicitly = FxHashSet();
 
-            for trans_item in scx.translation_items().borrow().iter() {
+            for trans_item in translation_items {
                 let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
                 if trans_item.explicit_linkage(tcx).is_some() {
                     linkage_fixed_explicitly.insert(symbol_name.clone());
@@ -1011,8 +1012,8 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter {
 ///
 /// This list is later used by linkers to determine the set of symbols needed to
 /// be exposed from a dynamic library and it's also encoded into the metadata.
-pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
-    reachable.into_iter().filter(|&id| {
+pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
+    reachable.iter().cloned().filter(|&id| {
         // Next, we want to ignore some FFI functions that are not exposed from
         // this crate. Reachable FFI functions can be lumped into two
         // categories:
@@ -1064,7 +1065,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let krate = tcx.hir.krate();
 
     let ty::CrateAnalysis { reachable, .. } = analysis;
-    let exported_symbols = find_exported_symbols(tcx, reachable);
+    let exported_symbols = find_exported_symbols(tcx, &reachable);
 
     let check_overflow = tcx.sess.overflow_checks();
 
@@ -1109,9 +1110,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Run the translation item collector and partition the collected items into
     // codegen units.
-    let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx);
-
-    let symbol_map = Rc::new(symbol_map);
+    let (translation_items, codegen_units, symbol_map) =
+        collect_and_partition_translation_items(&shared_ccx);
 
     let mut all_stats = Stats::default();
     let modules: Vec<ModuleTranslation> = codegen_units
@@ -1121,7 +1121,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let (stats, module) =
                 tcx.dep_graph.with_task(dep_node,
                                         AssertDepGraphSafe(&shared_ccx),
-                                        AssertDepGraphSafe((cgu, symbol_map.clone())),
+                                        AssertDepGraphSafe(cgu),
                                         module_translation);
             all_stats.extend(stats);
             module
@@ -1130,16 +1130,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     fn module_translation<'a, 'tcx>(
         scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
-        args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc<SymbolMap<'tcx>>)>)
+        args: AssertDepGraphSafe<CodegenUnit<'tcx>>)
         -> (Stats, ModuleTranslation)
     {
         // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
         let AssertDepGraphSafe(scx) = scx;
-        let AssertDepGraphSafe((cgu, symbol_map)) = args;
+        let AssertDepGraphSafe(cgu) = args;
 
         let cgu_name = String::from(cgu.name());
         let cgu_id = cgu.work_product_id();
-        let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map);
+        let symbol_cache = SymbolCache::new(scx.tcx());
+        let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache);
 
         // Check whether there is a previous work-product we can
         // re-use.  Not only must the file exist, and the inputs not
@@ -1174,11 +1175,11 @@ fn module_translation<'a, 'tcx>(
         }
 
         // Instantiate translation items without filling out definitions yet...
-        let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone());
+        let lcx = LocalCrateContext::new(scx, cgu, &symbol_cache);
         let module = {
             let ccx = CrateContext::new(scx, &lcx);
             let trans_items = ccx.codegen_unit()
-                                 .items_in_deterministic_order(ccx.tcx(), &symbol_map);
+                                 .items_in_deterministic_order(ccx.tcx(), &symbol_cache);
             for &(trans_item, linkage) in &trans_items {
                 trans_item.predefine(&ccx, linkage);
             }
@@ -1238,7 +1239,7 @@ fn module_translation<'a, 'tcx>(
 
     assert_module_sources::assert_module_sources(tcx, &modules);
 
-    symbol_names_test::report_symbol_names(&shared_ccx);
+    symbol_names_test::report_symbol_names(tcx);
 
     if shared_ccx.sess().trans_stats() {
         println!("--- trans stats ---");
@@ -1289,6 +1290,7 @@ fn module_translation<'a, 'tcx>(
     time(shared_ccx.sess().time_passes(), "internalize symbols", || {
         internalize_symbols(sess,
                             &shared_ccx,
+                            &translation_items,
                             &llvm_modules,
                             &symbol_map,
                             &exported_symbols);
@@ -1517,7 +1519,9 @@ enum Fields<'a> {
 }
 
 fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-                                                     -> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
+                                                     -> (FxHashSet<TransItem<'tcx>>,
+                                                         Vec<CodegenUnit<'tcx>>,
+                                                         SymbolMap<'tcx>) {
     let time_passes = scx.sess().time_passes();
 
     let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
@@ -1563,13 +1567,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
     assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() ||
             scx.tcx().sess.opts.debugging_opts.incremental.is_some());
 
-    {
-        let mut ccx_map = scx.translation_items().borrow_mut();
-
-        for trans_item in items.iter().cloned() {
-            ccx_map.insert(trans_item);
-        }
-    }
+    let translation_items: FxHashSet<TransItem<'tcx>> = items.iter().cloned().collect();
 
     if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
         let mut item_to_cgus = FxHashMap();
@@ -1624,5 +1622,5 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         }
     }
 
-    (codegen_units, symbol_map)
+    (translation_items, codegen_units, symbol_map)
 }
index 8b1010d89fd9fd1c03c5f0e657de371ae090529c..5103ca5c5e1094ef94b66bbbe65a497e07f21cd7 100644 (file)
@@ -477,24 +477,28 @@ pub fn not(&self, v: ValueRef) -> ValueRef {
         }
     }
 
-    pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+    pub fn alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
         let builder = Builder::with_ccx(self.ccx);
         builder.position_at_start(unsafe {
             llvm::LLVMGetFirstBasicBlock(self.llfn())
         });
-        builder.dynamic_alloca(ty, name)
+        builder.dynamic_alloca(ty, name, align)
     }
 
-    pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
+    pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
         self.count_insn("alloca");
         unsafe {
-            if name.is_empty() {
+            let alloca = if name.is_empty() {
                 llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
             } else {
                 let name = CString::new(name).unwrap();
                 llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
                                       name.as_ptr())
+            };
+            if let Some(align) = align {
+                llvm::LLVMSetAlignment(alloca, align as c_uint);
             }
+            alloca
         }
     }
 
index aefee51191ac4e3804efe66880ab7d32ee1ce5ac..264e26e4594ca04c88baf6a33cb2c8fd7a09a401 100644 (file)
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use llvm::{self, ValueRef};
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
 use attributes;
 use common::{self, CrateContext};
-use monomorphize;
 use consts;
 use declare;
-use monomorphize::Instance;
+use llvm::{self, ValueRef};
+use monomorphize::{self, Instance};
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, TypeFoldable};
+use rustc::ty::subst::Substs;
+use syntax_pos::DUMMY_SP;
 use trans_item::TransItem;
 use type_of;
-use rustc::ty::TypeFoldable;
 
 /// Translates a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -51,8 +51,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         return llfn;
     }
 
-    let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
-                                              TransItem::Fn(instance));
+    let sym = ccx.symbol_cache().get(TransItem::Fn(instance));
     debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
 
     // This is subtle and surprising, but sometimes we have to bitcast
@@ -102,15 +101,17 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let attrs = instance.def.attrs(ccx.tcx());
         attributes::from_fn_attrs(ccx, &attrs, llfn);
 
-        let is_local_def = ccx.shared().translation_items().borrow()
-                              .contains(&TransItem::Fn(instance));
-        if is_local_def {
-            // FIXME(eddyb) Doubt all extern fn should allow unwinding.
+        // Perhaps questionable, but we assume that anything defined
+        // *in Rust code* may unwind. Foreign items like `extern "C" {
+        // fn foo(); }` are assumed not to unwind **unless** they have
+        // a `#[unwind]` attribute.
+        if !ty::queries::is_foreign_item::get(tcx, DUMMY_SP, instance.def_id()) {
             attributes::unwind(llfn, true);
             unsafe {
                 llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
             }
         }
+
         if ccx.use_dll_storage_attrs() &&
             ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id())
         {
index ba2b807d5a01c9496fc7f1967faf00644576a28f..13bb0d371250f98b5490b9c0696db0cc2548adff 100644 (file)
@@ -467,13 +467,11 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
-                let target_ty = monomorphize::apply_param_substs(self.scx,
-                                                                 self.param_substs,
-                                                                 &target_ty);
+                let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                        &target_ty);
                 let source_ty = operand.ty(self.mir, self.scx.tcx());
-                let source_ty = monomorphize::apply_param_substs(self.scx,
-                                                                 self.param_substs,
-                                                                 &source_ty);
+                let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                        &source_ty);
                 let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
                                                                             source_ty,
                                                                             target_ty);
@@ -489,10 +487,8 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
             }
             mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => {
                 let fn_ty = operand.ty(self.mir, self.scx.tcx());
-                let fn_ty = monomorphize::apply_param_substs(
-                    self.scx,
-                    self.param_substs,
-                    &fn_ty);
+                let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                    &fn_ty);
                 visit_fn_use(self.scx, fn_ty, false, &mut self.output);
             }
             mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
@@ -534,9 +530,8 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location)
         }
 
         if let mir::Literal::Item { def_id, substs } = constant.literal {
-            let substs = monomorphize::apply_param_substs(self.scx,
-                                                          self.param_substs,
-                                                          &substs);
+            let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                 &substs);
             let instance = monomorphize::resolve(self.scx, def_id, substs);
             collect_neighbours(self.scx, instance, self.output);
         }
@@ -552,17 +547,14 @@ fn visit_terminator_kind(&mut self,
         match *kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.mir, tcx);
-                let callee_ty = monomorphize::apply_param_substs(
-                    self.scx, self.param_substs, &callee_ty);
+                let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
                 visit_fn_use(self.scx, callee_ty, true, &mut self.output);
             }
             mir::TerminatorKind::Drop { ref location, .. } |
             mir::TerminatorKind::DropAndReplace { ref location, .. } => {
                 let ty = location.ty(self.mir, self.scx.tcx())
                     .to_ty(self.scx.tcx());
-                let ty = monomorphize::apply_param_substs(self.scx,
-                                                          self.param_substs,
-                                                          &ty);
+                let ty = tcx.trans_apply_param_substs(self.param_substs, &ty);
                 visit_drop_use(self.scx, ty, true, self.output);
             }
             mir::TerminatorKind::Goto { .. } |
index 5d58c93538922ab6544adb417c5c1827b396551e..648ea92c8437601d22f7dd62d6c068dc1adea136 100644 (file)
@@ -564,7 +564,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
                         -> Ty<'tcx>
 {
     let ty = shared.tcx().item_type(def_id);
-    monomorphize::apply_param_substs(shared, substs, &ty)
+    shared.tcx().trans_apply_param_substs(substs, &ty)
 }
 
 /// Return the substituted type of an instance.
@@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
                              -> Ty<'tcx>
 {
     let ty = instance.def.def_ty(shared.tcx());
-    monomorphize::apply_param_substs(shared, instance.substs, &ty)
+    shared.tcx().trans_apply_param_substs(instance.substs, &ty)
 }
index 7a53a03344fcba2046f7a20e15f5679ffe72e4fa..3d614cfbcbf3c5c5f961a0d8b5b361c2df6274e2 100644 (file)
@@ -93,20 +93,19 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
             hir_map::NodeItem(&hir::Item {
                 ref attrs, span, node: hir::ItemStatic(..), ..
             }) => {
-                let sym = ccx.symbol_map()
-                             .get(TransItem::Static(id))
-                             .expect("Local statics should always be in the SymbolMap");
+                let sym = ccx.symbol_cache()
+                             .get(TransItem::Static(id));
 
                 let defined_in_current_codegen_unit = ccx.codegen_unit()
                                                          .items()
                                                          .contains_key(&TransItem::Static(id));
                 assert!(!defined_in_current_codegen_unit);
 
-                if declare::get_declared_value(ccx, sym).is_some() {
+                if declare::get_declared_value(ccx, &sym[..]).is_some() {
                     span_bug!(span, "trans: Conflicting symbol names for static?");
                 }
 
-                let g = declare::define_global(ccx, sym, llty).unwrap();
+                let g = declare::define_global(ccx, &sym[..], llty).unwrap();
 
                 (g, attrs)
             }
@@ -114,7 +113,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
             hir_map::NodeForeignItem(&hir::ForeignItem {
                 ref attrs, span, node: hir::ForeignItemStatic(..), ..
             }) => {
-                let sym = symbol_names::symbol_name(instance, ccx.shared());
+                let sym = symbol_names::symbol_name(instance, ccx.tcx());
                 let g = if let Some(name) =
                         attr::first_attr_value_str_by_name(&attrs, "linkage") {
                     // If this is a static with a linkage specified, then we need to handle
@@ -174,7 +173,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
 
         g
     } else {
-        let sym = symbol_names::symbol_name(instance, ccx.shared());
+        let sym = symbol_names::symbol_name(instance, ccx.tcx());
 
         // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
         // FIXME(nagisa): investigate whether it can be changed into define_global
@@ -261,8 +260,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // As an optimization, all shared statics which do not have interior
         // mutability are placed into read-only memory.
         if m != hir::MutMutable {
-            let tcontents = ty.type_contents(ccx.tcx());
-            if !tcontents.interior_unsafe() {
+            if ccx.shared().type_is_freeze(ty) {
                 llvm::LLVMSetGlobalConstant(g, llvm::True);
             }
         }
index c3770470bfd056536d620c38affa728d11e11aa7..bef22cf304dcb938f962c7e58c50429617807efb 100644 (file)
@@ -10,7 +10,7 @@
 
 use llvm;
 use llvm::{ContextRef, ModuleRef, ValueRef};
-use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use rustc::dep_graph::{DepGraph, DepGraphSafe};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::traits;
@@ -21,7 +21,6 @@
 use monomorphize::Instance;
 
 use partitioning::CodegenUnit;
-use trans_item::TransItem;
 use type_::Type;
 use rustc_data_structures::base_n;
 use rustc::ty::subst::Substs;
 use session::config::NoDebugInfo;
 use session::Session;
 use session::config;
-use symbol_map::SymbolMap;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
+use symbol_cache::SymbolCache;
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 
 use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
-use std::marker::PhantomData;
 use std::ptr;
 use std::iter;
-use std::rc::Rc;
 use std::str;
 use syntax::ast;
 use syntax::symbol::InternedString;
@@ -86,17 +83,13 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     check_overflow: bool,
 
     use_dll_storage_attrs: bool,
-
-    translation_items: RefCell<FxHashSet<TransItem<'tcx>>>,
-    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
-    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
 /// per compilation unit.  Each one has its own LLVM `ContextRef` so that
 /// several compilation units may be optimized in parallel.  All other LLVM
 /// data structures in the `LocalCrateContext` are tied to that `ContextRef`.
-pub struct LocalCrateContext<'tcx> {
+pub struct LocalCrateContext<'a, 'tcx: 'a> {
     llmod: ModuleRef,
     llcx: ContextRef,
     stats: Stats,
@@ -168,60 +161,10 @@ pub struct LocalCrateContext<'tcx> {
     /// Depth of the current type-of computation - used to bail out
     type_of_depth: Cell<usize>,
 
-    symbol_map: Rc<SymbolMap<'tcx>>,
-
     /// A counter that is used for generating local symbol names
     local_gen_sym_counter: Cell<usize>,
-}
-
-// Implement DepTrackingMapConfig for `trait_cache`
-pub struct TraitSelectionCache<'tcx> {
-    data: PhantomData<&'tcx ()>
-}
-
-impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
-    type Key = ty::PolyTraitRef<'tcx>;
-    type Value = traits::Vtable<'tcx, ()>;
-    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
-        key.to_poly_trait_predicate().dep_node()
-    }
-}
-
-// # Global Cache
 
-pub struct ProjectionCache<'gcx> {
-    data: PhantomData<&'gcx ()>
-}
-
-impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
-    type Key = Ty<'gcx>;
-    type Value = Ty<'gcx>;
-    fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
-        // Ideally, we'd just put `key` into the dep-node, but we
-        // can't put full types in there. So just collect up all the
-        // def-ids of structs/enums as well as any traits that we
-        // project out of. It doesn't matter so much what we do here,
-        // except that if we are too coarse, we'll create overly
-        // coarse edges between impls and the trans. For example, if
-        // we just used the def-id of things we are projecting out of,
-        // then the key for `<Foo as SomeTrait>::T` and `<Bar as
-        // SomeTrait>::T` would both share a dep-node
-        // (`TraitSelect(SomeTrait)`), and hence the impls for both
-        // `Foo` and `Bar` would be considered inputs. So a change to
-        // `Bar` would affect things that just normalized `Foo`.
-        // Anyway, this heuristic is not ideal, but better than
-        // nothing.
-        let def_ids: Vec<DefId> =
-            key.walk()
-               .filter_map(|t| match t.sty {
-                   ty::TyAdt(adt_def, _) => Some(adt_def.did),
-                   ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
-                   _ => None,
-               })
-               .collect();
-
-        DepNode::ProjectionCache { def_ids: def_ids }
-    }
+    symbol_cache: &'a SymbolCache<'a, 'tcx>,
 }
 
 /// A CrateContext value binds together one LocalCrateContext with the
@@ -229,12 +172,12 @@ fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
 /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans.
 pub struct CrateContext<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
-    local_ccx: &'a LocalCrateContext<'tcx>,
+    local_ccx: &'a LocalCrateContext<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> CrateContext<'a, 'tcx> {
     pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>,
-               local_ccx: &'a LocalCrateContext<'tcx>)
+               local_ccx: &'a LocalCrateContext<'a, 'tcx>)
                -> Self {
         CrateContext { shared, local_ccx }
     }
@@ -385,30 +328,23 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
             tcx: tcx,
             check_overflow: check_overflow,
             use_dll_storage_attrs: use_dll_storage_attrs,
-            translation_items: RefCell::new(FxHashSet()),
-            trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
-            project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
         }
     }
 
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env)
+        ty.needs_drop(self.tcx, &self.empty_param_env)
     }
 
     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
         ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
     }
 
-    pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
-        &self.exported_symbols
-    }
-
-    pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
-        &self.trait_cache
+    pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
+        ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP)
     }
 
-    pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
-        &self.project_cache
+    pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
+        &self.exported_symbols
     }
 
     pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
@@ -426,17 +362,13 @@ pub fn dep_graph<'a>(&'a self) -> &'a DepGraph {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.use_dll_storage_attrs
     }
-
-    pub fn translation_items(&self) -> &RefCell<FxHashSet<TransItem<'tcx>>> {
-        &self.translation_items
-    }
 }
 
-impl<'tcx> LocalCrateContext<'tcx> {
-    pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
-                   codegen_unit: CodegenUnit<'tcx>,
-                   symbol_map: Rc<SymbolMap<'tcx>>)
-                   -> LocalCrateContext<'tcx> {
+impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
+    pub fn new(shared: &SharedCrateContext<'a, 'tcx>,
+               codegen_unit: CodegenUnit<'tcx>,
+               symbol_cache: &'a SymbolCache<'a, 'tcx>)
+               -> LocalCrateContext<'a, 'tcx> {
         unsafe {
             // Append ".rs" to LLVM module identifier.
             //
@@ -490,8 +422,8 @@ pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
                 rust_try_fn: Cell::new(None),
                 intrinsics: RefCell::new(FxHashMap()),
                 type_of_depth: Cell::new(0),
-                symbol_map: symbol_map,
                 local_gen_sym_counter: Cell::new(0),
+                symbol_cache: symbol_cache,
             };
 
             let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
@@ -525,9 +457,9 @@ pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
     /// This is used in the `LocalCrateContext` constructor to allow calling
     /// functions that expect a complete `CrateContext`, even before the local
     /// portion is fully initialized and attached to the `SharedCrateContext`.
-    fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>,
-                     local_ccxs: &'a [LocalCrateContext<'tcx>])
-                     -> CrateContext<'a, 'tcx> {
+    fn dummy_ccx(shared: &'a SharedCrateContext<'a, 'tcx>,
+                 local_ccxs: &'a [LocalCrateContext<'a, 'tcx>])
+                 -> CrateContext<'a, 'tcx> {
         assert!(local_ccxs.len() == 1);
         CrateContext {
             shared: shared,
@@ -545,7 +477,7 @@ pub fn shared(&self) -> &'b SharedCrateContext<'b, 'tcx> {
         self.shared
     }
 
-    fn local(&self) -> &'b LocalCrateContext<'tcx> {
+    fn local(&self) -> &'b LocalCrateContext<'b, 'tcx> {
         self.local_ccx
     }
 
@@ -712,12 +644,8 @@ pub fn use_dll_storage_attrs(&self) -> bool {
         self.shared.use_dll_storage_attrs()
     }
 
-    pub fn symbol_map(&self) -> &SymbolMap<'tcx> {
-        &*self.local().symbol_map
-    }
-
-    pub fn translation_items(&self) -> &RefCell<FxHashSet<TransItem<'tcx>>> {
-        &self.shared.translation_items
+    pub fn symbol_cache(&self) -> &'b SymbolCache<'b, 'tcx> {
+        self.local().symbol_cache
     }
 
     /// Given the def-id of some item that has no type parameters, make
@@ -843,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
     type TyLayout = TyLayout<'tcx>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
+            return TyLayout { ty: ty, layout: layout, variant_index: None };
+        }
+
         self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
             infcx.layout_of(ty).unwrap_or_else(|e| {
                 match e {
@@ -853,6 +785,10 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
             })
         })
     }
+
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx().normalize_associated_type(&ty)
+    }
 }
 
 impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
@@ -861,9 +797,13 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.shared.layout_of(ty)
     }
+
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.shared.normalize_projections(ty)
+    }
 }
 
-pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
+pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>);
 
 impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> {
     fn drop(&mut self) {
index 7077eade61182af2387119e8dd0801d8e3b48062..54e20f590c6718350bd22c1b4326402202f4cc63 100644 (file)
@@ -778,7 +778,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         //
         // More information can be found in libstd's seh.rs implementation.
         let i64p = Type::i64(ccx).ptr_to();
-        let slot = bcx.alloca(i64p, "slot");
+        let slot = bcx.alloca(i64p, "slot", None);
         bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
             None);
 
index be214a0f6143cdb5b751fdddd9fbc3e851d6c127..117d8568500b8a61176374b31d56aa5cc49d64b5 100644 (file)
@@ -124,6 +124,7 @@ pub mod back {
 mod mir;
 mod monomorphize;
 mod partitioning;
+mod symbol_cache;
 mod symbol_map;
 mod symbol_names_test;
 mod trans_item;
index 0f5a38ac7f6b886343372514dd9ce887baa29a08..d94d7f4430bf006bfb0ed196e888c24e42e06c8b 100644 (file)
@@ -15,6 +15,7 @@
 use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
+use adt;
 use base::{self, Lifetime};
 use callee;
 use builder::Builder;
@@ -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.memory_ty(bcx.ccx), "ret");
+                            let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret", None);
                             self.store_operand(&bcx, llscratch, None, op);
                             llscratch
                         }
@@ -630,7 +631,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.memory_ty(bcx.ccx), "arg");
+                    let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None);
                     self.store_operand(bcx, llscratch, None, op);
                     (llscratch, Alignment::AbiAligned, true)
                 } else {
@@ -642,7 +643,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.memory_ty(bcx.ccx), "arg");
+                let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None);
                 base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
                 (llscratch, Alignment::AbiAligned, true)
             }
@@ -711,7 +712,8 @@ fn trans_arguments_untupled(&mut self,
                     bug!("Not a tuple.");
                 };
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize);
+                    let mut elem = bcx.extract_value(
+                        llval, adt::struct_llfields_index(v, n));
                     // Truncate bools to i1, if needed
                     if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) {
                         elem = bcx.trunc(elem, Type::i1(bcx.ccx));
@@ -750,7 +752,7 @@ fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
             slot
         } else {
             let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
-            let slot = bcx.alloca(llretty, "personalityslot");
+            let slot = bcx.alloca(llretty, "personalityslot", None);
             self.llpersonalityslot = Some(slot);
             slot
         }
index 8bce0cf85c08bf57184704e1ea55a88fc69c489a..040194e63d07e0ec6f549244ec495d3f3951abae 100644 (file)
@@ -100,15 +100,13 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
+            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
+            ConstVal::Variant(_) |
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) => {
                 bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
             }
-            ConstVal::Function(..) => {
-                let llty = type_of::type_of(ccx, ty);
-                return Const::new(C_null(llty), ty);
-            }
-            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
         };
 
         assert!(!ty.has_erasable_regions());
@@ -260,9 +258,7 @@ fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
     fn monomorphize<T>(&self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        monomorphize::apply_param_substs(self.ccx.shared(),
-                                         self.substs,
-                                         value)
+        self.ccx.tcx().trans_apply_param_substs(self.substs, value)
     }
 
     fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
@@ -710,7 +706,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
 
                 let ty = tr_lvalue.ty;
-                let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
+                let ref_ty = tcx.mk_ref(tcx.types.re_erased,
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
 
                 let base = match tr_lvalue.base {
index fc889604ab88ea900c50afd2ac1e24d04e8b4078..88e46b5c99a44186a4a033e4ff630544049555c1 100644 (file)
@@ -97,7 +97,8 @@ pub fn new_sized_ty(llval: ValueRef, ty: Ty<'tcx>, alignment: Alignment) -> Lval
 
     pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> {
         debug!("alloca({:?}: {:?})", name, ty);
-        let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name);
+        let tmp = bcx.alloca(
+            type_of::type_of(bcx.ccx, ty), name, bcx.ccx.over_align_of(ty));
         assert!(!ty.has_param_types());
         Self::new_sized_ty(tmp, ty, Alignment::AbiAligned)
     }
@@ -131,11 +132,9 @@ fn struct_field_ptr(
 
         let alignment = self.alignment | Alignment::from_packed(st.packed);
 
+        let llfields = adt::struct_llfields(ccx, fields, st);
         let ptr_val = if needs_cast {
-            let fields = st.field_index_by_increasing_offset().map(|i| {
-                type_of::in_memory_type_of(ccx, fields[i])
-            }).collect::<Vec<_>>();
-            let real_ty = Type::struct_(ccx, &fields[..], st.packed);
+            let real_ty = Type::struct_(ccx, &llfields[..], st.packed);
             bcx.pointercast(self.llval, real_ty.ptr_to())
         } else {
             self.llval
@@ -147,14 +146,16 @@ fn struct_field_ptr(
         //   * Field is sized - pointer is properly aligned already
         if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
             bcx.ccx.shared().type_is_sized(fty) {
-                return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
+                return (bcx.struct_gep(
+                        ptr_val, adt::struct_llfields_index(st, ix)), alignment);
             }
 
         // If the type of the last field is [T] or str, then we don't need to do
         // any adjusments
         match fty.sty {
             ty::TySlice(..) | ty::TyStr => {
-                return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
+                return (bcx.struct_gep(
+                        ptr_val, adt::struct_llfields_index(st, ix)), alignment);
             }
             _ => ()
         }
@@ -163,7 +164,7 @@ fn struct_field_ptr(
         if !self.has_extra() {
             debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
                 ix, Value(ptr_val));
-            return (bcx.struct_gep(ptr_val, ix), alignment);
+            return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment);
         }
 
         // We need to get the pointer manually now.
index 3d8c5085462a8c55150feca10016cb3db3dccfe2..af0e27c8ca391e69823b80d7f1e07432acb2b5ee 100644 (file)
@@ -22,7 +22,7 @@
 use builder::Builder;
 use common::{self, CrateContext, Funclet};
 use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
-use monomorphize::{self, Instance};
+use monomorphize::Instance;
 use abi::FnType;
 use type_of;
 
@@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> {
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx> {
-        monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value)
+        where T: TransNormalize<'tcx>
+    {
+        self.ccx.tcx().trans_apply_param_substs(self.param_substs, value)
     }
 
     pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) {
@@ -524,7 +525,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             // doesn't actually strip the offset when splitting the closure
             // environment into its components so it ends up out of bounds.
             let env_ptr = if !env_ref {
-                let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr");
+                let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr", None);
                 bcx.store(llval, alloc, None);
                 alloc
             } else {
index c31142323c85f56f8514978e701f82d548b85ee6..6889b5064b649a9bf0098566e73503b256bd3943 100644 (file)
@@ -15,6 +15,7 @@
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
 
+use adt;
 use base;
 use common::{self, CrateContext, C_null};
 use builder::Builder;
@@ -134,6 +135,12 @@ pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
                 if common::val_ty(elem) == Type::i1(bcx.ccx) {
                     elem = bcx.zext(elem, Type::i8(bcx.ccx));
                 }
+                let layout = bcx.ccx.layout_of(self.ty);
+                let i = if let Layout::Univariant { ref variant, .. } = *layout {
+                    adt::struct_llfields_index(variant, i)
+                } else {
+                    i
+                };
                 llpair = bcx.insert_value(llpair, elem, i);
             }
             self.val = OperandValue::Immediate(llpair);
@@ -183,14 +190,17 @@ pub fn trans_load(&mut self,
             let (lldata, llextra) = base::load_fat_ptr(bcx, llval, align, ty);
             OperandValue::Pair(lldata, llextra)
         } else if common::type_is_imm_pair(bcx.ccx, ty) {
-            let f_align = match *bcx.ccx.layout_of(ty) {
-                Layout::Univariant { ref variant, .. } =>
-                    Alignment::from_packed(variant.packed) | align,
-                _ => align
+            let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(ty) {
+                Layout::Univariant { ref variant, .. } => {
+                    (adt::struct_llfields_index(variant, 0),
+                    adt::struct_llfields_index(variant, 1),
+                    Alignment::from_packed(variant.packed) | align)
+                },
+                _ => (0, 1, align)
             };
             let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap();
-            let a_ptr = bcx.struct_gep(llval, 0);
-            let b_ptr = bcx.struct_gep(llval, 1);
+            let a_ptr = bcx.struct_gep(llval, ix0);
+            let b_ptr = bcx.struct_gep(llval, ix1);
 
             OperandValue::Pair(
                 base::load_ty(bcx, a_ptr, f_align, a_ty),
@@ -302,17 +312,19 @@ pub fn store_operand(&mut self,
                 bcx.store(base::from_immediate(bcx, s), lldest, align);
             }
             OperandValue::Pair(a, b) => {
-                let f_align = match *bcx.ccx.layout_of(operand.ty) {
-                    Layout::Univariant { ref variant, .. } if variant.packed => {
-                        Some(1)
+                let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(operand.ty) {
+                    Layout::Univariant { ref variant, .. } => {
+                        (adt::struct_llfields_index(variant, 0),
+                        adt::struct_llfields_index(variant, 1),
+                        if variant.packed { Some(1) } else { None })
                     }
-                    _ => align
+                    _ => (0, 1, align)
                 };
 
                 let a = base::from_immediate(bcx, a);
                 let b = base::from_immediate(bcx, b);
-                bcx.store(a, bcx.struct_gep(lldest, 0), f_align);
-                bcx.store(b, bcx.struct_gep(lldest, 1), f_align);
+                bcx.store(a, bcx.struct_gep(lldest, ix0), f_align);
+                bcx.store(b, bcx.struct_gep(lldest, ix1), f_align);
             }
         }
     }
index 98e9008f829f683fbbcea1e6b9f63e9ad8a6dd41..b8e9a490b0e7cffa36b0ce40812131c19ebd8382 100644 (file)
@@ -130,10 +130,12 @@ pub fn trans_rvalue(&mut self,
                     _ => {
                         // If this is a tuple or closure, we need to translate GEP indices.
                         let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx()));
-                        let translation = if let Layout::Univariant { ref variant, .. } = *layout {
-                            Some(&variant.memory_index)
-                        } else {
-                            None
+                        let get_memory_index = |i| {
+                            if let Layout::Univariant { ref variant, .. } = *layout {
+                                adt::struct_llfields_index(variant, i)
+                            } else {
+                                i
+                            }
                         };
                         let alignment = dest.alignment;
                         for (i, operand) in operands.iter().enumerate() {
@@ -143,11 +145,7 @@ pub fn trans_rvalue(&mut self,
                                 // Note: perhaps this should be StructGep, but
                                 // note that in some cases the values here will
                                 // not be structs but arrays.
-                                let i = if let Some(ref t) = translation {
-                                    t[i] as usize
-                                } else {
-                                    i
-                                };
+                                let i = get_memory_index(i);
                                 let dest = bcx.gepi(dest.llval, &[0, i]);
                                 self.store_operand(&bcx, dest, alignment.to_align(), op);
                             }
@@ -331,7 +329,7 @@ pub fn trans_rvalue_operand(&mut self,
 
                 let ty = tr_lvalue.ty.to_ty(bcx.tcx());
                 let ref_ty = bcx.tcx().mk_ref(
-                    bcx.tcx().mk_region(ty::ReErased),
+                    bcx.tcx().types.re_erased,
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }
                 );
 
index 382ca8ef01001ecfd31d922b869d143d5e3a04a0..d27eeb2b64667b712d8f1939cae832eb3a828dab 100644 (file)
 use glue;
 
 use rustc::hir::def_id::DefId;
-use rustc::infer::TransNormalize;
 use rustc::middle::lang_items::DropInPlaceFnLangItem;
-use rustc::traits::{self, SelectionContext, Reveal};
+use rustc::traits;
 use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::ty::fold::{TypeFolder, TypeFoldable};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::common::MemoizationMap;
 
-use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::DUMMY_SP;
 
 pub use rustc::ty::Instance;
 
@@ -104,73 +100,6 @@ pub fn resolve_closure<'a, 'tcx> (
     }
 }
 
-/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
-/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
-/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
-fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                span: Span,
-                                trait_ref: ty::PolyTraitRef<'tcx>)
-                                -> traits::Vtable<'tcx, ()>
-{
-    let tcx = scx.tcx();
-
-    // Remove any references to regions; this helps improve caching.
-    let trait_ref = tcx.erase_regions(&trait_ref);
-
-    scx.trait_cache().memoize(trait_ref, || {
-        debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
-               trait_ref, trait_ref.def_id());
-
-        // Do the initial selection for the obligation. This yields the
-        // shallow result we are looking for -- that is, what specific impl.
-        tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
-            let mut selcx = SelectionContext::new(&infcx);
-
-            let obligation_cause = traits::ObligationCause::misc(span,
-                                                             ast::DUMMY_NODE_ID);
-            let obligation = traits::Obligation::new(obligation_cause,
-                                                     trait_ref.to_poly_trait_predicate());
-
-            let selection = match selcx.select(&obligation) {
-                Ok(Some(selection)) => selection,
-                Ok(None) => {
-                    // Ambiguity can happen when monomorphizing during trans
-                    // expands to some humongo type that never occurred
-                    // statically -- this humongo type can then overflow,
-                    // leading to an ambiguous result. So report this as an
-                    // overflow bug, since I believe this is the only case
-                    // where ambiguity can result.
-                    debug!("Encountered ambiguity selecting `{:?}` during trans, \
-                            presuming due to overflow",
-                           trait_ref);
-                    tcx.sess.span_fatal(span,
-                        "reached the recursion limit during monomorphization \
-                         (selection ambiguity)");
-                }
-                Err(e) => {
-                    span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
-                              e, trait_ref)
-                }
-            };
-
-            debug!("fulfill_obligation: selection={:?}", selection);
-
-            // Currently, we use a fulfillment context to completely resolve
-            // all nested obligations. This is because they can inform the
-            // inference of the impl's type parameters.
-            let mut fulfill_cx = traits::FulfillmentContext::new();
-            let vtable = selection.map(|predicate| {
-                debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
-                fulfill_cx.register_predicate_obligation(&infcx, predicate);
-            });
-            let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
-
-            info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
-            vtable
-        })
-    })
-}
-
 fn resolve_associated_item<'a, 'tcx>(
     scx: &SharedCrateContext<'a, 'tcx>,
     trait_item: &ty::AssociatedItem,
@@ -185,7 +114,7 @@ fn resolve_associated_item<'a, 'tcx>(
            def_id, trait_id, rcvr_substs);
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
-    let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref));
+    let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref));
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
@@ -285,7 +214,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
         substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty])
     });
 
-    match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
+    match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) {
         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
             scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
         }
@@ -295,21 +224,6 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
     }
 }
 
-/// Monomorphizes a type from the AST by first applying the in-scope
-/// substitutions and then normalizing any associated types.
-pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
-                                       param_substs: &Substs<'tcx>,
-                                       value: &T)
-                                       -> T
-    where T: TransNormalize<'tcx>
-{
-    let tcx = scx.tcx();
-    debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
-    let substituted = value.subst(tcx, param_substs);
-    let substituted = scx.tcx().erase_regions(&substituted);
-    AssociatedTypeNormalizer::new(scx).fold(&substituted)
-}
-
 /// Returns the normalized type of a struct field
 pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           param_substs: &Substs<'tcx>,
@@ -319,39 +233,3 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.normalize_associated_type(&f.ty(tcx, param_substs))
 }
 
-struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> {
-    shared: &'a SharedCrateContext<'b, 'gcx>,
-}
-
-impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
-    fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self {
-        AssociatedTypeNormalizer {
-            shared: shared,
-        }
-    }
-
-    fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
-        if !value.has_projection_types() {
-            value.clone()
-        } else {
-            value.fold_with(self)
-        }
-    }
-}
-
-impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> {
-    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
-        self.shared.tcx()
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
-        if !ty.has_projection_types() {
-            ty
-        } else {
-            self.shared.project_cache().memoize(ty, || {
-                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
-                self.shared.tcx().normalize_associated_type(&ty)
-            })
-        }
-    }
-}
index 4973181202eeddcea8a787e66e53b42cecaba165..6b89d11cfb68f161e9356ba6934a46e943f306bc 100644 (file)
 use std::cmp::Ordering;
 use std::hash::Hash;
 use std::sync::Arc;
-use symbol_map::SymbolMap;
+use symbol_cache::SymbolCache;
 use syntax::ast::NodeId;
 use syntax::symbol::{Symbol, InternedString};
 use trans_item::{TransItem, InstantiationMode};
@@ -174,14 +174,15 @@ pub fn work_product_dep_node(&self) -> DepNode<DefId> {
         DepNode::WorkProduct(self.work_product_id())
     }
 
-    pub fn compute_symbol_name_hash(&self,
-                                    scx: &SharedCrateContext,
-                                    symbol_map: &SymbolMap) -> u64 {
+    pub fn compute_symbol_name_hash<'a>(&self,
+                                        scx: &SharedCrateContext<'a, 'tcx>,
+                                        symbol_cache: &SymbolCache<'a, 'tcx>)
+                                        -> u64 {
         let mut state = IchHasher::new();
         let exported_symbols = scx.exported_symbols();
-        let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map);
+        let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache);
         for (item, _) in all_items {
-            let symbol_name = symbol_map.get(item).unwrap();
+            let symbol_name = symbol_cache.get(item);
             symbol_name.len().hash(&mut state);
             symbol_name.hash(&mut state);
             let exported = match item {
@@ -201,10 +202,10 @@ pub fn compute_symbol_name_hash(&self,
         state.finish().to_smaller_hash()
     }
 
-    pub fn items_in_deterministic_order(&self,
-                                        tcx: TyCtxt,
-                                        symbol_map: &SymbolMap)
-                                        -> Vec<(TransItem<'tcx>, llvm::Linkage)> {
+    pub fn items_in_deterministic_order<'a>(&self,
+                                            tcx: TyCtxt,
+                                            symbol_cache: &SymbolCache<'a, 'tcx>)
+                                            -> Vec<(TransItem<'tcx>, llvm::Linkage)> {
         let mut items: Vec<(TransItem<'tcx>, llvm::Linkage)> =
             self.items.iter().map(|(item, linkage)| (*item, *linkage)).collect();
 
@@ -216,9 +217,9 @@ pub fn items_in_deterministic_order(&self,
 
             match (node_id1, node_id2) {
                 (None, None) => {
-                    let symbol_name1 = symbol_map.get(trans_item1).unwrap();
-                    let symbol_name2 = symbol_map.get(trans_item2).unwrap();
-                    symbol_name1.cmp(symbol_name2)
+                    let symbol_name1 = symbol_cache.get(trans_item1);
+                    let symbol_name2 = symbol_cache.get(trans_item2);
+                    symbol_name1.cmp(&symbol_name2)
                 }
                 // In the following two cases we can avoid looking up the symbol
                 (None, Some(_)) => Ordering::Less,
@@ -230,9 +231,9 @@ pub fn items_in_deterministic_order(&self,
                         return ordering;
                     }
 
-                    let symbol_name1 = symbol_map.get(trans_item1).unwrap();
-                    let symbol_name2 = symbol_map.get(trans_item2).unwrap();
-                    symbol_name1.cmp(symbol_name2)
+                    let symbol_name1 = symbol_cache.get(trans_item1);
+                    let symbol_name2 = symbol_cache.get(trans_item2);
+                    symbol_name1.cmp(&symbol_name2)
                 }
             }
         });
@@ -271,14 +272,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
     let mut initial_partitioning = place_root_translation_items(scx,
                                                                 trans_items);
 
-    debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
+    debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
 
     // If the partitioning should produce a fixed count of codegen units, merge
     // until that count is reached.
     if let PartitioningStrategy::FixedUnitCount(count) = strategy {
         merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str());
 
-        debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter());
+        debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
     }
 
     // In the next step, we use the inlining map to determine which addtional
@@ -288,7 +289,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
     let post_inlining = place_inlined_translation_items(initial_partitioning,
                                                         inlining_map);
 
-    debug_dump(scx, "POST INLINING:", post_inlining.0.iter());
+    debug_dump(tcx, "POST INLINING:", post_inlining.0.iter());
 
     // Finally, sort by codegen unit name, so that we get deterministic results
     let mut result = post_inlining.0;
@@ -528,7 +529,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString
     Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str()
 }
 
-fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
+fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                label: &str,
                                cgus: I)
     where I: Iterator<Item=&'b CodegenUnit<'tcx>>,
@@ -536,20 +537,18 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
 {
     if cfg!(debug_assertions) {
         debug!("{}", label);
+        let symbol_cache = SymbolCache::new(tcx);
         for cgu in cgus {
-            let symbol_map = SymbolMap::build(scx, cgu.items
-                                                      .iter()
-                                                      .map(|(&trans_item, _)| trans_item));
             debug!("CodegenUnit {}:", cgu.name);
 
             for (trans_item, linkage) in &cgu.items {
-                let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
+                let symbol_name = symbol_cache.get(*trans_item);
                 let symbol_hash_start = symbol_name.rfind('h');
                 let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..])
                                                    .unwrap_or("<no hash>");
 
                 debug!(" - {} [{:?}] [{}]",
-                       trans_item.to_string(scx.tcx()),
+                       trans_item.to_string(tcx),
                        linkage,
                        symbol_hash);
             }
diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs
new file mode 100644 (file)
index 0000000..ddc1ef5
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+use rustc::ty::TyCtxt;
+use std::cell::RefCell;
+use syntax_pos::symbol::{InternedString, Symbol};
+use trans_item::TransItem;
+use util::nodemap::FxHashMap;
+
+// In the SymbolCache we collect the symbol names of translation items
+// and cache them for later reference. This is just a performance
+// optimization and the cache is populated lazilly; symbol names of
+// translation items are deterministic and fully defined by the item.
+// Thus they can always be recomputed if needed.
+
+pub struct SymbolCache<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    index: RefCell<FxHashMap<TransItem<'tcx>, Symbol>>,
+}
+
+impl<'a, 'tcx> SymbolCache<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        SymbolCache {
+            tcx: tcx,
+            index: RefCell::new(FxHashMap())
+        }
+    }
+
+    pub fn get(&self, trans_item: TransItem<'tcx>) -> InternedString {
+        let mut index = self.index.borrow_mut();
+        index.entry(trans_item)
+             .or_insert_with(|| Symbol::intern(&trans_item.compute_symbol_name(self.tcx)))
+             .as_str()
+    }
+}
index 36c3981e3a6f240c2b78538f8a8e03a4ac8ed4c4..9d3e62888a2df1fadb22b8088c4d2a2de74875a2 100644 (file)
@@ -34,8 +34,9 @@ pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>,
         where I: Iterator<Item=TransItem<'tcx>>
     {
         // Check for duplicate symbol names
+        let tcx = scx.tcx();
         let mut symbols: Vec<_> = trans_items.map(|trans_item| {
-            (trans_item, trans_item.compute_symbol_name(scx))
+            (trans_item, trans_item.compute_symbol_name(tcx))
         }).collect();
 
         (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
@@ -124,7 +125,7 @@ pub fn get_or_compute<'map, 'scx>(&'map self,
         if let Some(sym) = self.get(trans_item) {
             Cow::from(sym)
         } else {
-            Cow::from(trans_item.compute_symbol_name(scx))
+            Cow::from(trans_item.compute_symbol_name(scx.tcx()))
         }
     }
 }
index fe551b06b3d95cff1b7e774139d7fbd99f5a19d9..fd817cb94c1c1db1251d73e7ea84c6832a300d47 100644 (file)
 use back::symbol_names;
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::ty::TyCtxt;
 use syntax::ast;
 
-use common::SharedCrateContext;
 use monomorphize::Instance;
 
 const SYMBOL_NAME: &'static str = "rustc_symbol_name";
 const ITEM_PATH: &'static str = "rustc_item_path";
 
-pub fn report_symbol_names(scx: &SharedCrateContext) {
+pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
-    let tcx = scx.tcx();
     if !tcx.sess.features.borrow().rustc_attrs {
         return;
     }
 
     let _ignore = tcx.dep_graph.in_ignore();
-    let mut visitor = SymbolNamesTest { scx: scx };
+    let mut visitor = SymbolNamesTest { tcx: tcx };
     // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
     tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
 
 struct SymbolNamesTest<'a, 'tcx:'a> {
-    scx: &'a SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
     fn process_attrs(&mut self,
                      node_id: ast::NodeId) {
-        let tcx = self.scx.tcx();
+        let tcx = self.tcx;
         let def_id = tcx.hir.local_def_id(node_id);
         for attr in tcx.get_attrs(def_id).iter() {
             if attr.check_name(SYMBOL_NAME) {
                 // for now, can only use on monomorphic names
                 let instance = Instance::mono(tcx, def_id);
-                let name = symbol_names::symbol_name(instance, self.scx);
+                let name = symbol_names::symbol_name(instance, self.tcx);
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
             } else if attr.check_name(ITEM_PATH) {
                 let path = tcx.item_path_str(def_id);
index 4d908f3c94fa58c7e2bda52885741b14ff6dc437..de35d1b7dd4c96330d46d06e479386e179c27a32 100644 (file)
@@ -18,7 +18,7 @@
 use attributes;
 use base;
 use consts;
-use context::{CrateContext, SharedCrateContext};
+use context::CrateContext;
 use common;
 use declare;
 use llvm;
@@ -118,8 +118,7 @@ pub fn predefine(&self,
                self.to_raw_string(),
                ccx.codegen_unit().name());
 
-        let symbol_name = ccx.symbol_map()
-                             .get_or_compute(ccx.shared(), *self);
+        let symbol_name = ccx.symbol_cache().get(*self);
 
         debug!("symbol {}", &symbol_name);
 
@@ -185,16 +184,15 @@ fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
         ccx.instances().borrow_mut().insert(instance, lldecl);
     }
 
-    pub fn compute_symbol_name(&self,
-                               scx: &SharedCrateContext<'a, 'tcx>) -> String {
+    pub fn compute_symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
         match *self {
-            TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx),
+            TransItem::Fn(instance) => symbol_names::symbol_name(instance, tcx),
             TransItem::Static(node_id) => {
-                let def_id = scx.tcx().hir.local_def_id(node_id);
-                symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx)
+                let def_id = tcx.hir.local_def_id(node_id);
+                symbol_names::symbol_name(Instance::mono(tcx, def_id), tcx)
             }
             TransItem::GlobalAsm(node_id) => {
-                let def_id = scx.tcx().hir.local_def_id(node_id);
+                let def_id = tcx.hir.local_def_id(node_id);
                 format!("global_asm_{:?}", def_id)
             }
         }
index d4ab6b0782855b7702c3b1fcfe030e4cf5aed512..9f9126ba83a8f19fd59b8f66b5196d3c3982dbb1 100644 (file)
@@ -214,6 +214,16 @@ pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
     pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
         self.layout_of(ty).size(self).bytes() as machine::llsize
     }
+
+    pub fn over_align_of(&self, t: Ty<'tcx>)
+                              -> Option<machine::llalign> {
+        let layout = self.layout_of(t);
+        if let Some(align) = layout.over_align(&self.tcx().data_layout) {
+            Some(align as machine::llalign)
+        } else {
+            None
+        }
+    }
 }
 
 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
index 9426d601dfcce3cc6b704d9e2ee5d0c85dcc408c..e0c67c1456d02a70224d9ec3329d701a30792088 100644 (file)
@@ -109,7 +109,7 @@ pub fn ast_region_to_region(&self,
         let tcx = self.tcx();
         let r = match tcx.named_region_map.defs.get(&lifetime.id) {
             Some(&rl::Region::Static) => {
-                tcx.mk_region(ty::ReStatic)
+                tcx.types.re_static
             }
 
             Some(&rl::Region::LateBound(debruijn, id)) => {
@@ -171,7 +171,7 @@ pub fn ast_path_substs_for_ty(&self,
                     .emit();
 
                 return Substs::for_item(tcx, def_id, |_, _| {
-                    tcx.mk_region(ty::ReStatic)
+                    tcx.types.re_static
                 }, |_, _| {
                     tcx.types.err
                 });
@@ -254,7 +254,7 @@ fn create_substs_for_ast_path(&self,
             if let Some(lifetime) = lifetimes.get(i) {
                 self.ast_region_to_region(lifetime, Some(def))
             } else {
-                tcx.mk_region(ty::ReStatic)
+                tcx.types.re_static
             }
         }, |def, substs| {
             let i = def.index as usize;
@@ -715,7 +715,7 @@ fn conv_object_ty_poly_trait_ref(&self,
                         span_err!(tcx.sess, span, E0228,
                                   "the lifetime bound for this object type cannot be deduced \
                                    from context; please supply an explicit bound");
-                        tcx.mk_region(ty::ReStatic)
+                        tcx.types.re_static
                     })
                 }
             })
@@ -903,10 +903,16 @@ pub fn associated_path_def_to_ty(&self,
         let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
         let ty = self.normalize_ty(span, ty);
 
-        let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name);
-        let def_id = item.expect("missing associated type").def_id;
-        tcx.check_stability(def_id, ref_id, span);
-        (ty, Def::AssociatedTy(def_id))
+        let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name)
+                                                  .expect("missing associated type");
+        let def = Def::AssociatedTy(item.def_id);
+        if !tcx.vis_is_accessible_from(item.vis, ref_id) {
+            let msg = format!("{} `{}` is private", def.kind_name(), assoc_name);
+            tcx.sess.span_err(span, &msg);
+        }
+        tcx.check_stability(item.def_id, ref_id, span);
+
+        (ty, def)
     }
 
     fn qpath_to_ty(&self,
@@ -1357,7 +1363,7 @@ fn compute_object_lifetime_bound(&self,
         // If any of the derived region bounds are 'static, that is always
         // the best choice.
         if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
-            return Some(tcx.mk_region(ty::ReStatic));
+            return Some(tcx.types.re_static);
         }
 
         // Determine whether there is exactly one unique region in the set
index 4a04464244442a2763b3c9124dc7074b35d31adc..1086773041c9351624a7fa86d249781634872bcc 100644 (file)
@@ -55,7 +55,7 @@ pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: boo
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
                         if let ty::TyRef(_, mt) = expected_ty.sty {
                             if let ty::TySlice(_) = mt.ty.sty {
-                                pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                                pat_ty = tcx.mk_imm_ref(tcx.types.re_static,
                                                          tcx.mk_slice(tcx.types.u8))
                             }
                         }
index c6a1f6cfc0d7fff01b72258e9ce19969dbd4ab55..d21b5f739bd7b5510712cc7eac3c43c44cfdf034 100644 (file)
@@ -78,6 +78,7 @@
 use syntax::abi;
 use syntax::feature_gate;
 use syntax::ptr::P;
+use syntax_pos;
 
 use std::collections::VecDeque;
 use std::ops::Deref;
@@ -722,6 +723,16 @@ pub fn try_coerce(&self,
         Ok(target)
     }
 
+    /// Same as `try_coerce()`, but without side-effects.
+    pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
+        let source = self.resolve_type_vars_with_obligations(expr_ty);
+        debug!("coercion::can({:?} -> {:?})", source, target);
+
+        let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
+        let coerce = Coerce::new(self, cause);
+        self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
+    }
+
     /// Given some expressions, their known unified type and another expression,
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
index e922c7447ff85384ceb3b9822e9f9058482ec33d..4cc3f2dacdfe996a77e4fc4c641595ce49109871 100644 (file)
 
 
 use check::FnCtxt;
-use rustc::ty::Ty;
-use rustc::infer::{InferOk};
+use rustc::infer::InferOk;
 use rustc::traits::ObligationCause;
 
 use syntax::ast;
 use syntax_pos::{self, Span};
 use rustc::hir;
 use rustc::hir::def::Def;
-use rustc::ty::{self, AssociatedItem};
+use rustc::ty::{self, Ty, AssociatedItem};
 use errors::DiagnosticBuilder;
 
 use super::method::probe;
@@ -80,18 +79,24 @@ pub fn demand_coerce(&self,
         if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
             let cause = self.misc(expr.span);
             let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
-            let mode = probe::Mode::MethodCall;
-            let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
-                                                         mode,
-                                                         expected,
-                                                         checked_ty,
-                                                         ast::DUMMY_NODE_ID);
             let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
-            if suggestions.len() > 0 {
-                err.help(&format!("here are some functions which \
-                                   might fulfill your needs:\n{}",
-                                  self.get_best_match(&suggestions).join("\n")));
-            };
+            if let Some(suggestion) = self.check_ref(expr,
+                                                     checked_ty,
+                                                     expected) {
+                err.help(&suggestion);
+            } else {
+                let mode = probe::Mode::MethodCall;
+                let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
+                                                             mode,
+                                                             expected,
+                                                             checked_ty,
+                                                             ast::DUMMY_NODE_ID);
+                if suggestions.len() > 0 {
+                    err.help(&format!("here are some functions which \
+                                       might fulfill your needs:\n{}",
+                                      self.get_best_match(&suggestions).join("\n")));
+                }
+            }
             err.emit();
         }
     }
@@ -140,4 +145,60 @@ fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
             _ => false,
         }
     }
+
+    /// This function is used to determine potential "simple" improvements or users' errors and
+    /// provide them useful help. For example:
+    ///
+    /// ```
+    /// fn some_fn(s: &str) {}
+    ///
+    /// let x = "hey!".to_owned();
+    /// some_fn(x); // error
+    /// ```
+    ///
+    /// No need to find every potential function which could make a coercion to transform a
+    /// `String` into a `&str` since a `&` would do the trick!
+    ///
+    /// In addition of this check, it also checks between references mutability state. If the
+    /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
+    /// `&mut`!".
+    fn check_ref(&self,
+                 expr: &hir::Expr,
+                 checked_ty: Ty<'tcx>,
+                 expected: Ty<'tcx>)
+                 -> Option<String> {
+        match (&expected.sty, &checked_ty.sty) {
+            (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
+            (&ty::TyRef(_, mutability), _) => {
+                // Check if it can work when put into a ref. For example:
+                //
+                // ```
+                // fn bar(x: &mut i32) {}
+                //
+                // let x = 0u32;
+                // bar(&x); // error, expected &mut
+                // ```
+                let ref_ty = match mutability.mutbl {
+                    hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
+                                                       self.tcx.mk_region(ty::ReStatic),
+                                                       checked_ty),
+                    hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
+                                                       self.tcx.mk_region(ty::ReStatic),
+                                                       checked_ty),
+                };
+                if self.can_coerce(ref_ty, expected) {
+                    if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
+                        return Some(format!("try with `{}{}`",
+                                            match mutability.mutbl {
+                                                hir::Mutability::MutMutable => "&mut ",
+                                                hir::Mutability::MutImmutable => "&",
+                                            },
+                                            &src));
+                    }
+                }
+                None
+            }
+            _ => None,
+        }
+    }
 }
index b71ff58ccec3305923fcf0085b165b9d607267e0..c125d7c02556fb2e67c317dc0ef70871113669ee 100644 (file)
 use rustc::infer::{self, InferOk};
 use middle::region;
 use rustc::ty::subst::{Subst, Substs};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::{self, ObligationCause, Reveal};
 use util::common::ErrorReported;
 use util::nodemap::FxHashSet;
 
-use syntax::ast;
 use syntax_pos::Span;
 
 /// check_drop_impl confirms that the Drop implementation identfied by
@@ -270,389 +269,64 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
 ///
 pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
     rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
-    typ: ty::Ty<'tcx>,
+    ty: ty::Ty<'tcx>,
     span: Span,
     scope: region::CodeExtent)
+    -> Result<(), ErrorReported>
 {
     debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
-           typ, scope);
+           ty, scope);
 
 
     let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) {
-      Some(parent_scope) => parent_scope,
-      // If no enclosing scope, then it must be the root scope which cannot be outlived.
-      None => return
+        Some(parent_scope) => parent_scope,
+        // If no enclosing scope, then it must be the root scope
+        // which cannot be outlived.
+        None => return Ok(())
     };
-
-    let result = iterate_over_potentially_unsafe_regions_in_type(
-        &mut DropckContext {
-            rcx: rcx,
-            span: span,
-            parent_scope: parent_scope,
-            breadcrumbs: FxHashSet()
-        },
-        TypeContext::Root,
-        typ,
-        0);
-    match result {
-        Ok(()) => {}
-        Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
-            let tcx = rcx.tcx;
-            let mut err = struct_span_err!(tcx.sess, span, E0320,
-                                           "overflow while adding drop-check rules for {}", typ);
-            match *ctxt {
-                TypeContext::Root => {
-                    // no need for an additional note if the overflow
-                    // was somehow on the root.
-                }
-                TypeContext::ADT { def_id, variant, field } => {
-                    let adt = tcx.lookup_adt_def(def_id);
-                    let variant_name = match adt.adt_kind() {
-                        AdtKind::Enum => format!("enum {} variant {}",
-                                                 tcx.item_path_str(def_id),
-                                                 variant),
-                        AdtKind::Struct => format!("struct {}",
-                                                   tcx.item_path_str(def_id)),
-                        AdtKind::Union => format!("union {}",
-                                                  tcx.item_path_str(def_id)),
-                    };
-                    span_note!(
-                        &mut err,
-                        span,
-                        "overflowed on {} field {} type: {}",
-                        variant_name,
-                        field,
-                        detected_on_typ);
+    let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
+    let origin = || infer::SubregionOrigin::SafeDestructor(span);
+
+    let ty = rcx.fcx.resolve_type_vars_if_possible(&ty);
+    let for_ty = ty;
+    let mut types = vec![(ty, 0)];
+    let mut known = FxHashSet();
+    while let Some((ty, depth)) = types.pop() {
+        let ty::DtorckConstraint {
+            dtorck_types, outlives
+        } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?;
+
+        for ty in dtorck_types {
+            let ty = rcx.fcx.normalize_associated_types_in(span, &ty);
+            let ty = rcx.fcx.resolve_type_vars_with_obligations(ty);
+            let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty);
+            match ty.sty {
+                // All parameters live for the duration of the
+                // function.
+                ty::TyParam(..) => {}
+
+                // A projection that we couldn't resolve - it
+                // might have a destructor.
+                ty::TyProjection(..) | ty::TyAnon(..) => {
+                    rcx.type_must_outlive(origin(), ty, parent_scope);
                 }
-            }
-            err.emit();
-        }
-    }
-}
-
-enum Error<'tcx> {
-    Overflow(TypeContext, ty::Ty<'tcx>),
-}
-
-#[derive(Copy, Clone)]
-enum TypeContext {
-    Root,
-    ADT {
-        def_id: DefId,
-        variant: ast::Name,
-        field: ast::Name,
-    }
-}
-
-struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
-    rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>,
-    /// types that have already been traversed
-    breadcrumbs: FxHashSet<Ty<'tcx>>,
-    /// span for error reporting
-    span: Span,
-    /// the scope reachable dtorck types must outlive
-    parent_scope: region::CodeExtent
-}
-
-// `context` is used for reporting overflow errors
-fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
-    cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>,
-    context: TypeContext,
-    ty: Ty<'tcx>,
-    depth: usize)
-    -> Result<(), Error<'tcx>>
-{
-    let tcx = cx.rcx.tcx;
-    // Issue #22443: Watch out for overflow. While we are careful to
-    // handle regular types properly, non-regular ones cause problems.
-    let recursion_limit = tcx.sess.recursion_limit.get();
-    if depth / 4 >= recursion_limit {
-        // This can get into rather deep recursion, especially in the
-        // presence of things like Vec<T> -> Unique<T> -> PhantomData<T> -> T.
-        // use a higher recursion limit to avoid errors.
-        return Err(Error::Overflow(context, ty))
-    }
 
-    // canoncialize the regions in `ty` before inserting - infinitely many
-    // region variables can refer to the same region.
-    let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty);
-
-    if !cx.breadcrumbs.insert(ty) {
-        debug!("iterate_over_potentially_unsafe_regions_in_type \
-               {}ty: {} scope: {:?} - cached",
-               (0..depth).map(|_| ' ').collect::<String>(),
-               ty, cx.parent_scope);
-        return Ok(()); // we already visited this type
-    }
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-           {}ty: {} scope: {:?}",
-           (0..depth).map(|_| ' ').collect::<String>(),
-           ty, cx.parent_scope);
-
-    // If `typ` has a destructor, then we must ensure that all
-    // borrowed data reachable via `typ` must outlive the parent
-    // of `scope`. This is handled below.
-    //
-    // However, there is an important special case: for any Drop
-    // impl that is tagged as "blind" to their parameters,
-    // we assume that data borrowed via such type parameters
-    // remains unreachable via that Drop impl.
-    //
-    // For example, consider:
-    //
-    // ```rust
-    // #[unsafe_destructor_blind_to_params]
-    // impl<T> Drop for Vec<T> { ... }
-    // ```
-    //
-    // which does have to be able to drop instances of `T`, but
-    // otherwise cannot read data from `T`.
-    //
-    // Of course, for the type expression passed in for any such
-    // unbounded type parameter `T`, we must resume the recursive
-    // analysis on `T` (since it would be ignored by
-    // type_must_outlive).
-    let dropck_kind = has_dtor_of_interest(tcx, ty);
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-            ty: {:?} dropck_kind: {:?}", ty, dropck_kind);
-    match dropck_kind {
-        DropckKind::NoBorrowedDataAccessedInMyDtor => {
-            // The maximally blind attribute.
-        }
-        DropckKind::BorrowedDataMustStrictlyOutliveSelf => {
-            cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
-                                     ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
-            return Ok(());
-        }
-        DropckKind::RevisedSelf(revised_ty) => {
-            cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
-                                     revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
-            // Do not return early from this case; we want
-            // to recursively process the internal structure of Self
-            // (because even though the Drop for Self has been asserted
-            //  safe, the types instantiated for the generics of Self
-            //  may themselves carry dropck constraints.)
-        }
-    }
-
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-           {}ty: {} scope: {:?} - checking interior",
-           (0..depth).map(|_| ' ').collect::<String>(),
-           ty, cx.parent_scope);
-
-    // We still need to ensure all referenced data is safe.
-    match ty.sty {
-        ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
-        ty::TyFloat(_) | ty::TyStr | ty::TyNever => {
-            // primitive - definitely safe
-            Ok(())
-        }
-
-        ty::TyArray(ity, _) | ty::TySlice(ity) => {
-            // single-element containers, behave like their element
-            iterate_over_potentially_unsafe_regions_in_type(
-                cx, context, ity, depth+1)
-        }
-
-        ty::TyAdt(def, substs) if def.is_phantom_data() => {
-            // PhantomData<T> - behaves identically to T
-            let ity = substs.type_at(0);
-            iterate_over_potentially_unsafe_regions_in_type(
-                cx, context, ity, depth+1)
-        }
-
-        ty::TyAdt(def, substs) => {
-            let did = def.did;
-            for variant in &def.variants {
-                for field in variant.fields.iter() {
-                    let fty = field.ty(tcx, substs);
-                    let fty = cx.rcx.fcx.resolve_type_vars_with_obligations(
-                        cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty));
-                    iterate_over_potentially_unsafe_regions_in_type(
-                        cx,
-                        TypeContext::ADT {
-                            def_id: did,
-                            field: field.name,
-                            variant: variant.name,
-                        },
-                        fty,
-                        depth+1)?
+                _ => {
+                    if let None = known.replace(ty) {
+                        types.push((ty, depth+1));
+                    }
                 }
             }
-            Ok(())
-        }
-
-        ty::TyClosure(def_id, substs) => {
-            for ty in substs.upvar_tys(def_id, tcx) {
-                iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
-            }
-            Ok(())
-        }
-
-        ty::TyTuple(tys, _) => {
-            for ty in tys {
-                iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
-            }
-            Ok(())
-        }
-
-        ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => {
-            // these always come with a witness of liveness (references
-            // explicitly, pointers implicitly, parameters by the
-            // caller).
-            Ok(())
         }
 
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-            // FIXME(#26656): this type is always destruction-safe, but
-            // it implicitly witnesses Self: Fn, which can be false.
-            Ok(())
-        }
-
-        ty::TyInfer(..) | ty::TyError => {
-            tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck");
-            Ok(())
-        }
-
-        // these are always dtorck
-        ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum DropckKind<'tcx> {
-    /// The "safe" kind; i.e. conservatively assume any borrow
-    /// accessed by dtor, and therefore such data must strictly
-    /// outlive self.
-    ///
-    /// Equivalent to RevisedTy with no change to the self type.
-    BorrowedDataMustStrictlyOutliveSelf,
-
-    /// The nearly completely-unsafe kind.
-    ///
-    /// Equivalent to RevisedSelf with *all* parameters remapped to ()
-    /// (maybe...?)
-    NoBorrowedDataAccessedInMyDtor,
-
-    /// Assume all borrowed data access by dtor occurs as if Self has the
-    /// type carried by this variant. In practice this means that some
-    /// of the type parameters are remapped to `()` (and some lifetime
-    /// parameters remapped to `'static`), because the developer has asserted
-    /// that the destructor will not access their contents.
-    RevisedSelf(Ty<'tcx>),
-}
-
-/// Returns the classification of what kind of check should be applied
-/// to `ty`, which may include a revised type where some of the type
-/// parameters are re-mapped to `()` to reflect the destructor's
-/// "purity" with respect to their actual contents.
-fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                        ty: Ty<'tcx>)
-                                        -> DropckKind<'tcx> {
-    match ty.sty {
-        ty::TyAdt(adt_def, substs) => {
-            if !adt_def.is_dtorck(tcx) {
-                return DropckKind::NoBorrowedDataAccessedInMyDtor;
+        for outlive in outlives {
+            if let Some(r) = outlive.as_region() {
+                rcx.sub_regions(origin(), parent_scope, r);
+            } else if let Some(ty) = outlive.as_type() {
+                rcx.type_must_outlive(origin(), ty, parent_scope);
             }
-
-            // Find the `impl<..> Drop for _` to inspect any
-            // attributes attached to the impl's generics.
-            let dtor_method = adt_def.destructor(tcx)
-                .expect("dtorck type without destructor impossible");
-            let method = tcx.associated_item(dtor_method.did);
-            let impl_def_id = method.container.id();
-            let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
-            return DropckKind::RevisedSelf(revised_ty);
-        }
-        ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
-            debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
-            return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
-        },
-        _ => {
-            return DropckKind::NoBorrowedDataAccessedInMyDtor;
         }
     }
-}
 
-// Constructs new Ty just like the type defined by `adt_def` coupled
-// with `substs`, except each type and lifetime parameter marked as
-// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is
-// respectively mapped to `()` or `'static`.
-//
-// For example: If the `adt_def` maps to:
-//
-//   enum Foo<'a, X, Y> { ... }
-//
-// and the `impl_def_id` maps to:
-//
-//   impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
-//
-// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
-fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                  adt_def: &'tcx ty::AdtDef,
-                                  impl_def_id: DefId,
-                                  substs: &Substs<'tcx>)
-                                  -> Ty<'tcx> {
-    // Get generics for `impl Drop` to query for `#[may_dangle]` attr.
-    let impl_bindings = tcx.item_generics(impl_def_id);
-
-    // Get Substs attached to Self on `impl Drop`; process in parallel
-    // with `substs`, replacing dangling entries as appropriate.
-    let self_substs = {
-        let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id);
-        if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty {
-            assert_eq!(adt_def, self_adt_def);
-            self_substs
-        } else {
-            bug!("Self in `impl Drop for _` must be an Adt.");
-        }
-    };
-
-    // Walk `substs` + `self_substs`, build new substs appropriate for
-    // `adt_def`; each non-dangling param reuses entry from `substs`.
-    //
-    // Note: The manner we map from a right-hand side (i.e. Region or
-    // Ty) for a given `def` to generic parameter associated with that
-    // right-hand side is tightly coupled to `Drop` impl constraints.
-    //
-    // E.g. we know such a Ty must be `TyParam`, because a destructor
-    // for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
-    // and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
-    let substs = Substs::for_item(
-        tcx,
-        adt_def.did,
-        |def, _| {
-            let r_orig = substs.region_for_def(def);
-            let impl_self_orig = self_substs.region_for_def(def);
-            let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig {
-                if impl_bindings.region_param(ebr).pure_wrt_drop {
-                    tcx.mk_region(ty::ReStatic)
-                } else {
-                    r_orig
-                }
-            } else {
-                bug!("substs for an impl must map regions to ReEarlyBound");
-            };
-            debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}",
-                   def, r_orig, r);
-            r
-        },
-        |def, _| {
-            let t_orig = substs.type_for_def(def);
-            let impl_self_orig = self_substs.type_for_def(def);
-            let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty {
-                if impl_bindings.type_param(pt).pure_wrt_drop {
-                    tcx.mk_nil()
-                } else {
-                    t_orig
-                }
-            } else {
-                bug!("substs for an impl must map types to TyParam");
-            };
-            debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}",
-                   def, t_orig, t_orig.sty, t, t.sty);
-            t
-        });
-
-    tcx.mk_adt(adt_def, &substs)
+    Ok(())
 }
index cd58fcd4806da62d104e61679c7a9527ae71bad6..bf7649242fa71c918b35bd782469c3bb21984b48 100644 (file)
@@ -36,7 +36,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def_id = tcx.hir.local_def_id(it.id);
 
     let substs = Substs::for_item(tcx, def_id,
-                                  |_, _| tcx.mk_region(ty::ReErased),
+                                  |_, _| tcx.types.re_erased,
                                   |def, _| tcx.mk_param_from_def(def));
 
     let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
index 7dd2699a6eaf08b224d7cafdb785178cdde52817..72fba1ef6ecca825c9fbf279e63170e0da18d947 100644 (file)
@@ -349,15 +349,8 @@ pub fn resolve_ufcs(&self,
         }
 
         let def = pick.item.def();
-
         self.tcx.check_stability(def.def_id(), expr_id, span);
 
-        if let probe::InherentImplPick = pick.kind {
-            if !self.tcx.vis_is_accessible_from(pick.item.vis, self.body_id) {
-                let msg = format!("{} `{}` is private", def.kind_name(), method_name);
-                self.tcx.sess.span_err(span, &msg);
-            }
-        }
         Ok(def)
     }
 
index 59dbbfe49f0a99848f3a712f02cd7fd808bf7eb5..26e8693d3b2aa441eb6a6e7fabb3471e5b0d0db0 100644 (file)
@@ -369,6 +369,24 @@ fn reset(&mut self) {
     ///////////////////////////////////////////////////////////////////////////
     // CANDIDATE ASSEMBLY
 
+    fn push_inherent_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem,
+                               kind: CandidateKind<'tcx>, import_id: Option<ast::NodeId>) {
+        if self.tcx.vis_is_accessible_from(item.vis, self.body_id) {
+            self.inherent_candidates.push(Candidate { xform_self_ty, item, kind, import_id });
+        } else if self.private_candidate.is_none() {
+            self.private_candidate = Some(item.def());
+        }
+    }
+
+    fn push_extension_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem,
+                               kind: CandidateKind<'tcx>, import_id: Option<ast::NodeId>) {
+        if self.tcx.vis_is_accessible_from(item.vis, self.body_id) {
+            self.extension_candidates.push(Candidate { xform_self_ty, item, kind, import_id });
+        } else if self.private_candidate.is_none() {
+            self.private_candidate = Some(item.def());
+        }
+    }
+
     fn assemble_inherent_candidates(&mut self) {
         let steps = self.steps.clone();
         for step in steps.iter() {
@@ -499,11 +517,6 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
                 continue
             }
 
-            if !self.tcx.vis_is_accessible_from(item.vis, self.body_id) {
-                self.private_candidate = Some(item.def());
-                continue
-            }
-
             let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
             let impl_ty = impl_ty.subst(self.tcx, impl_substs);
 
@@ -519,12 +532,8 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
             debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
                    xform_self_ty);
 
-            self.inherent_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item,
-                kind: InherentImplCandidate(impl_substs, obligations),
-                import_id: None,
-            });
+            self.push_inherent_candidate(xform_self_ty, item,
+                                         InherentImplCandidate(impl_substs, obligations), None);
         }
     }
 
@@ -548,12 +557,7 @@ fn assemble_inherent_candidates_from_object(&mut self,
             let xform_self_ty =
                 this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
 
-            this.inherent_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item,
-                kind: ObjectCandidate,
-                import_id: None,
-            });
+            this.push_inherent_candidate(xform_self_ty, item, ObjectCandidate, None);
         });
     }
 
@@ -599,12 +603,8 @@ fn assemble_inherent_candidates_from_param(&mut self,
             // `WhereClausePick`.
             assert!(!trait_ref.substs.needs_infer());
 
-            this.inherent_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item,
-                kind: WhereClauseCandidate(poly_trait_ref),
-                import_id: None,
-            });
+            this.push_inherent_candidate(xform_self_ty, item,
+                                         WhereClauseCandidate(poly_trait_ref), None);
         });
     }
 
@@ -743,12 +743,8 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
 
             debug!("xform_self_ty={:?}", xform_self_ty);
 
-            self.extension_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item.clone(),
-                kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations),
-                import_id: import_id,
-            });
+            self.push_extension_candidate(xform_self_ty, item,
+                        ExtensionImplCandidate(impl_def_id, impl_substs, obligations), import_id);
         });
     }
 
@@ -833,12 +829,7 @@ fn assemble_closure_candidates(&mut self,
             });
 
             let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
-            self.inherent_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item.clone(),
-                kind: TraitCandidate,
-                import_id: import_id,
-            });
+            self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id);
         }
 
         Ok(())
@@ -854,7 +845,7 @@ fn assemble_projection_candidates(&mut self,
                trait_def_id,
                item);
 
-        for step in self.steps.iter() {
+        for step in Rc::clone(&self.steps).iter() {
             debug!("assemble_projection_candidates: step={:?}", step);
 
             let (def_id, substs) = match step.self_ty.sty {
@@ -889,12 +880,7 @@ fn assemble_projection_candidates(&mut self,
                            bound,
                            xform_self_ty);
 
-                    self.extension_candidates.push(Candidate {
-                        xform_self_ty: xform_self_ty,
-                        item: item.clone(),
-                        kind: TraitCandidate,
-                        import_id: import_id,
-                    });
+                    self.push_extension_candidate(xform_self_ty, item, TraitCandidate, import_id);
                 }
             }
         }
@@ -918,12 +904,8 @@ fn assemble_where_clause_candidates(&mut self,
                    bound,
                    xform_self_ty);
 
-            self.extension_candidates.push(Candidate {
-                xform_self_ty: xform_self_ty,
-                item: item.clone(),
-                kind: WhereClauseCandidate(poly_bound),
-                import_id: import_id,
-            });
+            self.push_extension_candidate(xform_self_ty, item,
+                                          WhereClauseCandidate(poly_bound), import_id);
         }
     }
 
@@ -1063,7 +1045,7 @@ fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickRes
 
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
-        let region = tcx.mk_region(ty::ReErased);
+        let region = tcx.types.re_erased;
 
         // Search through mutabilities in order to find one where pick works:
         [hir::MutImmutable, hir::MutMutable]
@@ -1325,7 +1307,7 @@ fn xform_method_self_ty(&self,
                 } else {
                     // In general, during probe we erase regions. See
                     // `impl_self_ty()` for an explanation.
-                    self.tcx.mk_region(ty::ReErased)
+                    self.tcx.types.re_erased
                 }
             }, |def, cur_substs| {
                 let i = def.index as usize;
@@ -1345,7 +1327,7 @@ fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx
 
         let substs = Substs::for_item(self.tcx,
                                       impl_def_id,
-                                      |_, _| self.tcx.mk_region(ty::ReErased),
+                                      |_, _| self.tcx.types.re_erased,
                                       |_, _| self.next_ty_var(
                                         TypeVariableOrigin::SubstitutionPlaceholder(
                                             self.tcx.def_span(impl_def_id))));
index 902cfb889f8c209faa304568f3f5387db65ce3c1..098e8c53a52c12c89582022d77d05da0afcaebd4 100644 (file)
@@ -953,6 +953,12 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if def.repr.simd() {
         check_simd(tcx, span, def_id);
     }
+
+    // if struct is packed and not aligned, check fields for alignment.
+    // Checks for combining packed and align attrs on single struct are done elsewhere.
+    if tcx.lookup_adt_def(def_id).repr.packed() && tcx.lookup_adt_def(def_id).repr.align == 0 {
+        check_packed(tcx, span, def_id);
+    }
 }
 
 fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1371,6 +1377,47 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
     }
 }
 
+fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
+    if check_packed_inner(tcx, def_id, &mut Vec::new()) {
+        struct_span_err!(tcx.sess, sp, E0588,
+            "packed struct cannot transitively contain a `[repr(align)]` struct").emit();
+    }
+}
+
+fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                def_id: DefId,
+                                stack: &mut Vec<DefId>) -> bool {
+    let t = tcx.item_type(def_id);
+    if stack.contains(&def_id) {
+        debug!("check_packed_inner: {:?} is recursive", t);
+        return false;
+    }
+    match t.sty {
+        ty::TyAdt(def, substs) if def.is_struct() => {
+            if tcx.lookup_adt_def(def.did).repr.align > 0 {
+                return true;
+            }
+            // push struct def_id before checking fields
+            stack.push(def_id);
+            for field in &def.struct_variant().fields {
+                let f = field.ty(tcx, substs);
+                match f.sty {
+                    ty::TyAdt(def, _) => {
+                        if check_packed_inner(tcx, def.did, stack) {
+                            return true;
+                        }
+                    }
+                    _ => ()
+                }
+            }
+            // only need to pop if not early out
+            stack.pop();
+        }
+        _ => ()
+    }
+    false
+}
+
 #[allow(trivial_numeric_casts)]
 pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             sp: Span,
@@ -1907,7 +1954,7 @@ pub fn register_old_wf_obligation(&self,
         //
         // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
         let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause);
+        self.register_region_obligation(ty, self.tcx.types.re_empty, cause);
     }
 
     /// Registers obligations that all types appearing in `substs` are well-formed.
@@ -2466,7 +2513,7 @@ fn check_lit(&self,
         match lit.node {
             ast::LitKind::Str(..) => tcx.mk_static_str(),
             ast::LitKind::ByteStr(ref v) => {
-                tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                tcx.mk_imm_ref(tcx.types.re_static,
                                 tcx.mk_array(tcx.types.u8, v.len()))
             }
             ast::LitKind::Byte(_) => tcx.types.u8,
index 8bfb390bd2a5514d76727cc528c2c6b968c4dec8..dcef22da879646e6c4df0858d57d03f8ca948fae 100644 (file)
@@ -457,7 +457,8 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
             self.type_of_node_must_outlive(origin, id, var_region);
 
             let typ = self.resolve_node_type(id);
-            dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
+            let _ = dropck::check_safety_of_destructor_if_necessary(
+                self, typ, span, var_scope);
         })
     }
 }
@@ -995,10 +996,8 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
                 match *region {
                     ty::ReScope(rvalue_scope) => {
                         let typ = self.resolve_type(cmt.ty);
-                        dropck::check_safety_of_destructor_if_necessary(self,
-                                                                        typ,
-                                                                        span,
-                                                                        rvalue_scope);
+                        let _ = dropck::check_safety_of_destructor_if_necessary(
+                            self, typ, span, rvalue_scope);
                     }
                     ty::ReStatic => {}
                     _ => {
index f196aa82b1ef3ebc7a76da218e2a1de2b5b52e68..35b2e8f8afcb8eabce30c843e995b83a8f7b449f 100644 (file)
@@ -288,8 +288,8 @@ fn visit_anon_types(&mut self) {
             let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
                 match *r {
                     // 'static is valid everywhere.
-                    ty::ReStatic |
-                    ty::ReEmpty => gcx.mk_region(*r),
+                    ty::ReStatic => gcx.types.re_static,
+                    ty::ReEmpty => gcx.types.re_empty,
 
                     // Free regions that come from early-bound regions are valid.
                     ty::ReFree(ty::FreeRegion {
@@ -307,7 +307,7 @@ fn visit_anon_types(&mut self) {
                         span_err!(self.tcx().sess, span, E0564,
                                   "only named lifetimes are allowed in `impl Trait`, \
                                    but `{}` was found in the type `{}`", r, inside_ty);
-                        gcx.mk_region(ty::ReStatic)
+                        gcx.types.re_static
                     }
 
                     ty::ReVar(_) |
@@ -526,7 +526,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         match self.infcx.fully_resolve(&r) {
             Ok(r) => r,
             Err(_) => {
-                self.tcx.mk_region(ty::ReStatic)
+                self.tcx.types.re_static
             }
         }
     }
index af0ef279e4f0dfdc894524d9ea31fede68b117aa..660ce837043c1d02d6481d4396325e958730ed27 100644 (file)
@@ -99,6 +99,8 @@ pub fn provide(providers: &mut Providers) {
         trait_def,
         adt_def,
         impl_trait_ref,
+        impl_polarity,
+        is_foreign_item,
         ..*providers
     };
 }
@@ -553,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
             let expr_did = tcx.hir.local_def_id(e.node_id);
-            let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did);
+            let substs = Substs::empty();
+            let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs));
 
             // enum variant evaluation happens before the global constant check
             // so we need to report the real error
@@ -1132,6 +1135,16 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> hir::ImplPolarity {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    match tcx.hir.expect_item(node_id).node {
+        hir::ItemImpl(_, polarity, ..) => polarity,
+        ref item => bug!("trait_impl_polarity: {:?} not an impl", item)
+    }
+}
+
 // Is it marked with ?Sized
 fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                 ast_bounds: &[hir::TyParamBound],
@@ -1530,3 +1543,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
     let substs = Substs::identity_for_item(tcx, def_id);
     tcx.mk_fn_def(def_id, substs, fty)
 }
+
+fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             def_id: DefId)
+                             -> bool {
+    match tcx.hir.get_if_local(def_id) {
+        Some(hir_map::NodeForeignItem(..)) => true,
+        Some(_) => false,
+        _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id)
+    }
+}
index 68afcae2b674615c859d0490d6294eb031d5fa4b..2bae6a0d9e11a7e1bfe1e7d42d4797bd6d637ebe 100644 (file)
@@ -4154,7 +4154,6 @@ fn main() { }
 //  E0248, // value used as a type, now reported earlier during resolution as E0412
 //  E0249,
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
-    E0320, // recursive overflow during dropck
 //  E0372, // coherence not object safe
     E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures with the same definition
@@ -4168,5 +4167,6 @@ fn main() { }
            // but `{}` was found in the type `{}`
     E0567, // auto traits can not have type parameters
     E0568, // auto-traits can not have predicates,
+    E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
     E0592, // duplicate definitions with name `{}`
 }
index cc30fdf56fc346c08b411d8b027a6400cfbb33f1..6016fd488f56c8938e025e8c1783e85bde6d59ea 100644 (file)
@@ -487,7 +487,7 @@ fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
 }
 
 fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
-    let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+    let body = cx.tcx.sess.cstore.item_body(cx.tcx, did);
     let inlined = InlinedConst {
         nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
     };
index b02b60531d108dc41a7da893e09a03be59cb9aed..85a28bbfbc6d0bb0e636356327fbde67030cb00c 100644 (file)
@@ -32,6 +32,7 @@
 use std::cell::RefCell;
 use std::collections::{HashMap, VecDeque};
 use std::default::Default;
+use std::ffi::CString;
 use std::fmt::{self, Write};
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
 use html::render::derive_id;
 use html::toc::TocBuilder;
 use html::highlight;
+use html::escape::Escape;
 use test;
 
 use pulldown_cmark::{html, Event, Tag, Parser};
 use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
 
+#[derive(PartialEq, Debug, Clone, Copy)]
+pub enum RenderType {
+    Hoedown,
+    Pulldown,
+}
+
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
 // The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str);
+pub struct Markdown<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str);
+pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
-pub struct MarkdownHtml<'a>(pub &'a str);
+pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders only the first paragraph.
 pub struct MarkdownSummaryLine<'a>(pub &'a str);
 
@@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
     }
 }
 
+/// Returns a new string with all consecutive whitespace collapsed into
+/// single spaces.
+///
+/// Any leading or trailing whitespace will be trimmed.
+fn collapse_whitespace(s: &str) -> String {
+    s.split_whitespace().collect::<Vec<_>>().join(" ")
+}
+
 /// Convert chars from a title for an id.
 ///
 /// "Hello, world!" -> "hello-world"
@@ -368,6 +384,7 @@ fn next(&mut self) -> Option<Self::Item> {
 const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
 const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
 const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
+const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1;
 
 const HOEDOWN_EXTENSIONS: libc::c_uint =
     HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
@@ -462,6 +479,13 @@ struct hoedown_buffer {
     unit: libc::size_t,
 }
 
+struct MyOpaque {
+    dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
+                           *const hoedown_buffer, *const hoedown_renderer_data,
+                           libc::size_t),
+    toc_builder: Option<TocBuilder>,
+}
+
 extern {
     fn hoedown_html_renderer_new(render_flags: libc::c_uint,
                                  nesting_level: libc::c_int)
@@ -478,6 +502,7 @@ fn hoedown_document_render(doc: *mut hoedown_document,
     fn hoedown_document_free(md: *mut hoedown_document);
 
     fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
+    fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char);
     fn hoedown_buffer_free(b: *mut hoedown_buffer);
 }
 
@@ -487,6 +512,208 @@ fn as_bytes(&self) -> &[u8] {
     }
 }
 
+pub fn render(w: &mut fmt::Formatter,
+              s: &str,
+              print_toc: bool,
+              html_flags: libc::c_uint) -> fmt::Result {
+    extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
+                    lang: *const hoedown_buffer, data: *const hoedown_renderer_data,
+                    line: libc::size_t) {
+        unsafe {
+            if orig_text.is_null() { return }
+
+            let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
+            let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque);
+            let text = (*orig_text).as_bytes();
+            let origtext = str::from_utf8(text).unwrap();
+            let origtext = origtext.trim_left();
+            debug!("docblock: ==============\n{:?}\n=======", text);
+            let rendered = if lang.is_null() || origtext.is_empty() {
+                false
+            } else {
+                let rlang = (*lang).as_bytes();
+                let rlang = str::from_utf8(rlang).unwrap();
+                if !LangString::parse(rlang).rust {
+                    (my_opaque.dfltblk)(ob, orig_text, lang,
+                                        opaque as *const hoedown_renderer_data,
+                                        line);
+                    true
+                } else {
+                    false
+                }
+            };
+
+            let lines = origtext.lines().filter(|l| {
+                stripped_filtered_line(*l).is_none()
+            });
+            let text = lines.collect::<Vec<&str>>().join("\n");
+            if rendered { return }
+            PLAYGROUND.with(|play| {
+                // insert newline to clearly separate it from the
+                // previous block so we can shorten the html output
+                let mut s = String::from("\n");
+                let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
+                    if url.is_empty() {
+                        return None;
+                    }
+                    let test = origtext.lines().map(|l| {
+                        stripped_filtered_line(l).unwrap_or(l)
+                    }).collect::<Vec<&str>>().join("\n");
+                    let krate = krate.as_ref().map(|s| &**s);
+                    let test = test::maketest(&test, krate, false,
+                                              &Default::default());
+                    let channel = if test.contains("#![feature(") {
+                        "&amp;version=nightly"
+                    } else {
+                        ""
+                    };
+                    // These characters don't need to be escaped in a URI.
+                    // FIXME: use a library function for percent encoding.
+                    fn dont_escape(c: u8) -> bool {
+                        (b'a' <= c && c <= b'z') ||
+                        (b'A' <= c && c <= b'Z') ||
+                        (b'0' <= c && c <= b'9') ||
+                        c == b'-' || c == b'_' || c == b'.' ||
+                        c == b'~' || c == b'!' || c == b'\'' ||
+                        c == b'(' || c == b')' || c == b'*'
+                    }
+                    let mut test_escaped = String::new();
+                    for b in test.bytes() {
+                        if dont_escape(b) {
+                            test_escaped.push(char::from(b));
+                        } else {
+                            write!(test_escaped, "%{:02X}", b).unwrap();
+                        }
+                    }
+                    Some(format!(
+                        r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
+                        url, test_escaped, channel
+                    ))
+                });
+                s.push_str(&highlight::render_with_highlighting(
+                               &text,
+                               Some("rust-example-rendered"),
+                               None,
+                               playground_button.as_ref().map(String::as_str)));
+                let output = CString::new(s).unwrap();
+                hoedown_buffer_puts(ob, output.as_ptr());
+            })
+        }
+    }
+
+    extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
+                     level: libc::c_int, data: *const hoedown_renderer_data,
+                     _: libc::size_t) {
+        // hoedown does this, we may as well too
+        unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); }
+
+        // Extract the text provided
+        let s = if text.is_null() {
+            "".to_owned()
+        } else {
+            let s = unsafe { (*text).as_bytes() };
+            str::from_utf8(&s).unwrap().to_owned()
+        };
+
+        // Discard '<em>', '<code>' tags and some escaped characters,
+        // transform the contents of the header into a hyphenated string
+        // without non-alphanumeric characters other than '-' and '_'.
+        //
+        // This is a terrible hack working around how hoedown gives us rendered
+        // html for text rather than the raw text.
+        let mut id = s.clone();
+        let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
+                            "<strong>", "</strong>",
+                            "&lt;", "&gt;", "&amp;", "&#39;", "&quot;"];
+        for sub in repl_sub {
+            id = id.replace(sub, "");
+        }
+        let id = id.chars().filter_map(|c| {
+            if c.is_alphanumeric() || c == '-' || c == '_' {
+                if c.is_ascii() {
+                    Some(c.to_ascii_lowercase())
+                } else {
+                    Some(c)
+                }
+            } else if c.is_whitespace() && c.is_ascii() {
+                Some('-')
+            } else {
+                None
+            }
+        }).collect::<String>();
+
+        let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state };
+        let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
+
+        let id = derive_id(id);
+
+        let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| {
+            format!("{} ", builder.push(level as u32, s.clone(), id.clone()))
+        });
+
+        // Render the HTML
+        let text = format!("<h{lvl} id='{id}' class='section-header'>\
+                           <a href='#{id}'>{sec}{}</a></h{lvl}>",
+                           s, lvl = level, id = id, sec = sec);
+
+        let text = CString::new(text).unwrap();
+        unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
+    }
+
+    extern fn codespan(
+        ob: *mut hoedown_buffer,
+        text: *const hoedown_buffer,
+        _: *const hoedown_renderer_data,
+        _: libc::size_t
+    ) -> libc::c_int {
+        let content = if text.is_null() {
+            "".to_owned()
+        } else {
+            let bytes = unsafe { (*text).as_bytes() };
+            let s = str::from_utf8(bytes).unwrap();
+            collapse_whitespace(s)
+        };
+
+        let content = format!("<code>{}</code>", Escape(&content));
+        let element = CString::new(content).unwrap();
+        unsafe { hoedown_buffer_puts(ob, element.as_ptr()); }
+        // Return anything except 0, which would mean "also print the code span verbatim".
+        1
+    }
+
+    unsafe {
+        let ob = hoedown_buffer_new(DEF_OUNIT);
+        let renderer = hoedown_html_renderer_new(html_flags, 0);
+        let mut opaque = MyOpaque {
+            dfltblk: (*renderer).blockcode.unwrap(),
+            toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
+        };
+        (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
+                = &mut opaque as *mut _ as *mut libc::c_void;
+        (*renderer).blockcode = Some(block);
+        (*renderer).header = Some(header);
+        (*renderer).codespan = Some(codespan);
+
+        let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
+        hoedown_document_render(document, ob, s.as_ptr(),
+                                s.len() as libc::size_t);
+        hoedown_document_free(document);
+
+        hoedown_html_renderer_free(renderer);
+
+        let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| {
+            write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
+        });
+
+        if ret.is_ok() {
+            let buf = (*ob).as_bytes();
+            ret = w.write_str(str::from_utf8(buf).unwrap());
+        }
+        hoedown_buffer_free(ob);
+        ret
+    }
+}
+
 pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
     extern fn block(_ob: *mut hoedown_buffer,
                     text: *const hoedown_buffer,
@@ -503,11 +730,26 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
                 LangString::parse(s)
             };
             if !block_info.rust { return }
+            let text = (*text).as_bytes();
             let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
             let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
-            let line = tests.get_line() + line;
+            let text = str::from_utf8(text).unwrap();
+            let lines = text.lines().map(|l| {
+                stripped_filtered_line(l).unwrap_or(l)
+            });
+            let text = lines.collect::<Vec<&str>>().join("\n");
             let filename = tests.get_filename();
-            tests.add_old_test(line, filename);
+
+            if tests.render_type == RenderType::Hoedown {
+                let line = tests.get_line() + line;
+                tests.add_test(text.to_owned(),
+                               block_info.should_panic, block_info.no_run,
+                               block_info.ignore, block_info.test_harness,
+                               block_info.compile_fail, block_info.error_codes,
+                               line, filename);
+            } else {
+                tests.add_old_test(text, filename);
+            }
         }
     }
 
@@ -529,7 +771,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
     }
 
     tests.set_position(position);
-
     unsafe {
         let ob = hoedown_buffer_new(DEF_OUNIT);
         let renderer = hoedown_html_renderer_new(0, 0);
@@ -698,72 +939,84 @@ fn parse(string: &str) -> LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let Markdown(md) = *self;
+        let Markdown(md, render_type) = *self;
+
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, false, 0)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
-
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let MarkdownWithToc(md) = *self;
+        let MarkdownWithToc(md, render_type) = *self;
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, true, 0)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let mut toc = TocBuilder::new();
+            let mut toc = TocBuilder::new();
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
 
-        write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
+            write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
 impl<'a> fmt::Display for MarkdownHtml<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let MarkdownHtml(md) = *self;
+        let MarkdownHtml(md, render_type) = *self;
+
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, false, HOEDOWN_HTML_ESCAPE)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
-
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        // Treat inline HTML as plain text.
-        let p = p.map(|event| match event {
-            Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
-            _ => event
-        });
+            // Treat inline HTML as plain text.
+            let p = p.map(|event| match event {
+                Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
+                _ => event
+            });
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
@@ -837,6 +1090,7 @@ fn next(&mut self) -> Option<String> {
 mod tests {
     use super::{LangString, Markdown, MarkdownHtml};
     use super::plain_summary_line;
+    use super::RenderType;
     use html::render::reset_ids;
 
     #[test]
@@ -877,14 +1131,14 @@ fn t(s: &str,
     #[test]
     fn issue_17736() {
         let markdown = "# title";
-        format!("{}", Markdown(markdown));
+        format!("{}", Markdown(markdown, RenderType::Pulldown));
         reset_ids(true);
     }
 
     #[test]
     fn test_header() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input));
+            let output = format!("{}", Markdown(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
             reset_ids(true);
         }
@@ -906,7 +1160,7 @@ fn t(input: &str, expect: &str) {
     #[test]
     fn test_header_ids_multiple_blocks() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input));
+            let output = format!("{}", Markdown(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -947,7 +1201,7 @@ fn t(input: &str, expect: &str) {
     #[test]
     fn test_markdown_html_escape() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", MarkdownHtml(input));
+            let output = format!("{}", MarkdownHtml(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
         }
 
index d55a0640562aee2c336d089a2e72f7608d9aaf58..57d71e6c4e004e37b7542d6eb1eecf117c72f598 100644 (file)
@@ -72,7 +72,7 @@
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType};
 use html::{highlight, layout};
 
 /// A pair of name and its optional document.
@@ -98,6 +98,7 @@ pub struct Context {
     /// publicly reused items to redirect to the right location.
     pub render_redirect_pages: bool,
     pub shared: Arc<SharedContext>,
+    pub render_type: RenderType,
 }
 
 pub struct SharedContext {
@@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate,
            dst: PathBuf,
            passes: FxHashSet<String>,
            css_file_extension: Option<PathBuf>,
-           renderinfo: RenderInfo) -> Result<(), Error> {
+           renderinfo: RenderInfo,
+           render_type: RenderType) -> Result<(), Error> {
     let src_root = match krate.src.parent() {
         Some(p) => p.to_path_buf(),
         None => PathBuf::new(),
@@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate,
         dst: dst,
         render_redirect_pages: false,
         shared: Arc::new(scx),
+        render_type: render_type,
     };
 
     // Crawl the crate to build various caches used for the output
@@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String {
 
 fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
     document_stability(w, cx, item)?;
-    document_full(w, item)?;
+    document_full(w, item, cx.render_type)?;
     Ok(())
 }
 
-fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result {
+fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
+                  render_type: RenderType) -> fmt::Result {
     if let Some(s) = item.doc_value() {
         let markdown = if s.contains('\n') {
             format!("{} [Read more]({})",
@@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
             format!("{}", &plain_summary_line(Some(s)))
         };
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&markdown))?;
+               Markdown(&markdown, render_type))?;
     }
     Ok(())
 }
@@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
     }
 }
 
-fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
+fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
+                 render_type: RenderType) -> fmt::Result {
     if let Some(s) = get_doc_value(item) {
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?;
     }
     Ok(())
 }
@@ -1872,7 +1877,13 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
-                       docs = MarkdownSummaryLine(doc_value),
+                       docs = if cx.render_type == RenderType::Hoedown {
+                           format!("{}",
+                                   shorter(Some(&Markdown(doc_value,
+                                                          RenderType::Hoedown).to_string())))
+                       } else {
+                           format!("{}", MarkdownSummaryLine(doc_value))
+                       },
                        class = myitem.type_(),
                        stab = myitem.stability_class().unwrap_or("".to_string()),
                        unsafety_flag = unsafety_flag,
@@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
             } else {
                 String::new()
             };
-            let text = format!("Deprecated{}{}", since, MarkdownHtml(&deprecated_reason));
+            let text = format!("Deprecated{}{}",
+                               since,
+                               MarkdownHtml(&deprecated_reason, cx.render_type));
             stability.push(format!("<div class='stab deprecated'>{}</div>", text))
         };
 
@@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                     let text = format!("<summary><span class=microscope>🔬</span> \
                                         This is a nightly-only experimental API. {}\
                                         </summary>{}",
-                                       unstable_extra, MarkdownHtml(&stab.unstable_reason));
+                                       unstable_extra,
+                                       MarkdownHtml(&stab.unstable_reason, cx.render_type));
                     stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
                                    text));
                 }
@@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
             String::new()
         };
 
-        let text = format!("Deprecated{}{}", since, MarkdownHtml(&note));
+        let text = format!("Deprecated{}{}", since, MarkdownHtml(&note, cx.render_type));
         stability.push(format!("<div class='stab deprecated'>{}</div>", text))
     }
 
@@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
         if let Some(ref dox) = i.impl_item.doc_value() {
-            write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
+            write!(w, "<div class='docblock'>{}</div>", Markdown(dox, cx.render_type))?;
         }
     }
 
@@ -2999,11 +3013,11 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                         // because impls can't have a stability.
                         document_stability(w, cx, it)?;
                         if get_doc_value(item).is_some() {
-                            document_full(w, item)?;
+                            document_full(w, item, cx.render_type)?;
                         } else {
                             // In case the item isn't documented,
                             // provide short documentation from the trait.
-                            document_short(w, it, link)?;
+                            document_short(w, it, link, cx.render_type)?;
                         }
                     }
                 } else {
@@ -3011,7 +3025,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                 }
             } else {
                 document_stability(w, cx, item)?;
-                document_short(w, item, link)?;
+                document_short(w, item, link, cx.render_type)?;
             }
         }
         Ok(())
index d5b997001bb9deed6297102df90d603fb2737c53..2a6134fde5c3d8f8e9aaba8b30ee207590052184 100644 (file)
@@ -27,6 +27,7 @@
 #![feature(staged_api)]
 #![feature(test)]
 #![feature(unicode)]
+#![feature(vec_remove_item)]
 
 extern crate arena;
 extern crate getopts;
@@ -92,6 +93,8 @@ pub mod html {
 
 use clean::AttributesExt;
 
+use html::markdown::RenderType;
+
 struct Output {
     krate: clean::Crate,
     renderinfo: html::render::RenderInfo,
@@ -168,6 +171,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
                         "URL to send code snippets to, may be reset by --markdown-playground-url \
                          or `#![doc(html_playground_url=...)]`",
                         "URL")),
+        unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")),
     ]
 }
 
@@ -249,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize {
     let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
     let cfgs = matches.opt_strs("cfg");
 
+    let render_type = if matches.opt_present("enable-commonmark") {
+        RenderType::Pulldown
+    } else {
+        RenderType::Hoedown
+    };
+
     if let Some(ref p) = css_file_extension {
         if !p.is_file() {
             writeln!(
@@ -272,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize {
 
     match (should_test, markdown_input) {
         (true, true) => {
-            return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot)
+            return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type)
         }
         (true, false) => {
-            return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot)
+            return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
+                             render_type)
         }
         (false, true) => return markdown::render(input,
                                                  output.unwrap_or(PathBuf::from("doc")),
                                                  &matches, &external_html,
-                                                 !matches.opt_present("markdown-no-toc")),
+                                                 !matches.opt_present("markdown-no-toc"),
+                                                 render_type),
         (false, false) => {}
     }
 
@@ -294,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize {
                                   output.unwrap_or(PathBuf::from("doc")),
                                   passes.into_iter().collect(),
                                   css_file_extension,
-                                  renderinfo)
+                                  renderinfo,
+                                  render_type)
                     .expect("failed to generate documentation");
                 0
             }
index f75144c23aca9dac01277c17964809c10d6af225..b9ed0eeaef736715d814e34a0d04e51c10399855 100644 (file)
@@ -26,6 +26,7 @@
 use html::escape::Escape;
 use html::markdown;
 use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
+use html::markdown::RenderType;
 use test::{TestOptions, Collector};
 
 /// Separate any lines at the start of the file that begin with `# ` or `%`.
@@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
 /// Render `input` (e.g. "foo.md") into an HTML file in `output`
 /// (e.g. output = "bar" => "bar/foo.html").
 pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
-              external_html: &ExternalHtml, include_toc: bool) -> isize {
+              external_html: &ExternalHtml, include_toc: bool,
+              render_type: RenderType) -> isize {
     let input_p = Path::new(input);
     output.push(input_p.file_stem().unwrap());
     output.set_extension("html");
@@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     reset_ids(false);
 
     let rendered = if include_toc {
-        format!("{}", MarkdownWithToc(text))
+        format!("{}", MarkdownWithToc(text, render_type))
     } else {
-        format!("{}", Markdown(text))
+        format!("{}", Markdown(text, render_type))
     };
 
     let err = write!(
@@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
 /// Run any tests/code examples in the markdown file `input`.
 pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
-            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
+            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
+            render_type: RenderType) -> isize {
     let input_str = match load_string(input) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
@@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     opts.no_crate_inject = true;
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                        true, opts, maybe_sysroot, None,
-                                       Some(input.to_owned()));
+                                       Some(input.to_owned()),
+                                       render_type);
     old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
     find_testable_code(&input_str, &mut collector, DUMMY_SP);
     test_args.insert(0, "rustdoctest".to_string());
index fb681b20065fa3a9d70434aa59a92dc9657edf94..5b9ab304db0a9667ff27843166d7baca1aabf8d0 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::collections::HashMap;
 use std::env;
 use std::ffi::OsString;
 use std::io::prelude::*;
@@ -42,7 +43,7 @@
 use errors::emitter::ColorConfig;
 
 use clean::Attributes;
-use html::markdown;
+use html::markdown::{self, RenderType};
 
 #[derive(Clone, Default)]
 pub struct TestOptions {
@@ -56,7 +57,8 @@ pub fn run(input: &str,
            externs: Externs,
            mut test_args: Vec<String>,
            crate_name: Option<String>,
-           maybe_sysroot: Option<PathBuf>)
+           maybe_sysroot: Option<PathBuf>,
+           render_type: RenderType)
            -> isize {
     let input_path = PathBuf::from(input);
     let input = config::Input::File(input_path.clone());
@@ -105,7 +107,8 @@ pub fn run(input: &str,
                                        opts,
                                        maybe_sysroot,
                                        Some(codemap),
-                                       None);
+                                       None,
+                                       render_type);
 
     {
         let dep_graph = DepGraph::new(false);
@@ -381,7 +384,7 @@ fn partition_source(s: &str) -> (String, String) {
 pub struct Collector {
     pub tests: Vec<testing::TestDescAndFn>,
     // to be removed when hoedown will be definitely gone
-    pub old_tests: Vec<String>,
+    pub old_tests: HashMap<String, Vec<String>>,
     names: Vec<String>,
     cfgs: Vec<String>,
     libs: SearchPaths,
@@ -395,15 +398,18 @@ pub struct Collector {
     position: Span,
     codemap: Option<Rc<CodeMap>>,
     filename: Option<String>,
+    // to be removed when hoedown will be removed as well
+    pub render_type: RenderType,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
                use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
-               codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
+               codemap: Option<Rc<CodeMap>>, filename: Option<String>,
+               render_type: RenderType) -> Collector {
         Collector {
             tests: Vec::new(),
-            old_tests: Vec::new(),
+            old_tests: HashMap::new(),
             names: Vec::new(),
             cfgs: cfgs,
             libs: libs,
@@ -417,6 +423,7 @@ pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Ext
             position: DUMMY_SP,
             codemap: codemap,
             filename: filename,
+            render_type: render_type,
         }
     }
 
@@ -432,9 +439,24 @@ fn generate_name(&self, line: usize, filename: &str) -> String {
         }
     }
 
-    pub fn add_old_test(&mut self, line: usize, filename: String) {
-        let name = self.generate_name(line, &filename);
-        self.old_tests.push(name);
+    // to be removed once hoedown is gone
+    fn generate_name_beginning(&self, filename: &str) -> String {
+        if self.use_headers {
+            if let Some(ref header) = self.current_header {
+                format!("{} - {} (line", filename, header)
+            } else {
+                format!("{} - (line", filename)
+            }
+        } else {
+            format!("{} - {} (line", filename, self.names.join("::"))
+        }
+    }
+
+    pub fn add_old_test(&mut self, test: String, filename: String) {
+        let name_beg = self.generate_name_beginning(&filename);
+        let entry = self.old_tests.entry(name_beg)
+                                  .or_insert(Vec::new());
+        entry.push(test.trim().to_owned());
     }
 
     pub fn add_test(&mut self, test: String,
@@ -442,13 +464,22 @@ pub fn add_test(&mut self, test: String,
                     as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
                     line: usize, filename: String) {
         let name = self.generate_name(line, &filename);
-        if self.old_tests.iter().find(|&x| x == &name).is_none() {
-            let _ = writeln!(&mut io::stderr(),
-                             "WARNING: {} Code block is not currently run as a test, but will in \
-                              future versions of rustdoc. Please ensure this code block is a \
-                              runnable test, or use the `ignore` directive.",
-                             name);
-            return
+        // to be removed when hoedown is removed
+        if self.render_type == RenderType::Pulldown {
+            let name_beg = self.generate_name_beginning(&filename);
+            let mut found = false;
+            let test = test.trim().to_owned();
+            if let Some(entry) = self.old_tests.get_mut(&name_beg) {
+                found = entry.remove_item(&test).is_some();
+            }
+            if !found {
+                let _ = writeln!(&mut io::stderr(),
+                                 "WARNING: {} Code block is not currently run as a test, but will \
+                                  in future versions of rustdoc. Please ensure this code block is \
+                                  a runnable test, or use the `ignore` directive.",
+                                 name);
+                return
+            }
         }
         let cfgs = self.cfgs.clone();
         let libs = self.libs.clone();
@@ -564,10 +595,15 @@ fn visit_testable<F: FnOnce(&mut Self)>(&mut self,
         attrs.unindent_doc_comments();
         if let Some(doc) = attrs.doc_value() {
             self.collector.cnt = 0;
-            markdown::old_find_testable_code(doc, self.collector,
+            if self.collector.render_type == RenderType::Pulldown {
+                markdown::old_find_testable_code(doc, self.collector,
+                                                 attrs.span.unwrap_or(DUMMY_SP));
+                markdown::find_testable_code(doc, self.collector,
                                              attrs.span.unwrap_or(DUMMY_SP));
-            markdown::find_testable_code(doc, self.collector,
-                                         attrs.span.unwrap_or(DUMMY_SP));
+            } else {
+                markdown::old_find_testable_code(doc, self.collector,
+                                                 attrs.span.unwrap_or(DUMMY_SP));
+            }
         }
 
         nested(self);
index eacb59d375a5065885a0c884eeec45ab092cbefa..51d127f8ba79a246c33745356c94ab0888f4bf98 100644 (file)
@@ -1377,7 +1377,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 
 /// An owning iterator over the entries of a `HashMap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
+/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.HashMap.html#method.into_iter
@@ -2017,13 +2017,6 @@ pub fn key(&self) -> &K {
         self.elem.read().0
     }
 
-    /// Deprecated, renamed to `remove_entry`
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
-    pub fn remove_pair(self) -> (K, V) {
-        self.remove_entry()
-    }
-
     /// Take the ownership of the key and value from the map.
     ///
     /// # Examples
index e3fad28502573a7604ca0ddbb90744098a4ce413..7215e1bde8503e1988f14e3bcbcde373a58ab4a1 100644 (file)
@@ -890,7 +890,7 @@ pub struct Iter<'a, K: 'a> {
 
 /// An owning iterator over the items of a `HashSet`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`HashSet`]
+/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`HashSet`]: struct.HashSet.html
index 316e6841c4feabf562365d72fdda5b7159e1a749..4abad7e24f8107a6b2690399190104eec2bf07ba 100644 (file)
@@ -22,8 +22,6 @@
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
 use num::FpCategory;
 
 
@@ -73,8 +71,6 @@ mod cmath {
         pub fn atan2f(a: c_float, b: c_float) -> c_float;
         pub fn atanf(n: c_float) -> c_float;
         pub fn coshf(n: c_float) -> c_float;
-        pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
-        pub fn ldexpf(x: c_float, n: c_int) -> c_float;
         pub fn sinhf(n: c_float) -> c_float;
         pub fn tanf(n: c_float) -> c_float;
         pub fn tanhf(n: c_float) -> c_float;
@@ -84,7 +80,7 @@ mod cmath {
     pub use self::shims::*;
     #[cfg(target_env = "msvc")]
     mod shims {
-        use libc::{c_float, c_int};
+        use libc::c_float;
 
         #[inline]
         pub unsafe fn acosf(n: c_float) -> c_float {
@@ -111,20 +107,6 @@ pub unsafe fn coshf(n: c_float) -> c_float {
             f64::cosh(n as f64) as c_float
         }
 
-        #[inline]
-        #[allow(deprecated)]
-        pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
-            let (a, b) = f64::frexp(x as f64);
-            *value = b as c_int;
-            a as c_float
-        }
-
-        #[inline]
-        #[allow(deprecated)]
-        pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
-            f64::ldexp(x as f64, n as isize) as c_float
-        }
-
         #[inline]
         pub unsafe fn sinhf(n: c_float) -> c_float {
             f64::sinh(n as f64) as c_float
@@ -244,40 +226,6 @@ pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
     #[inline]
     pub fn classify(self) -> FpCategory { num::Float::classify(self) }
 
-    /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
-    /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
-    /// The floating point encoding is documented in the [Reference][floating-point].
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let num = 2.0f32;
-    ///
-    /// // (8388608, -22, 1)
-    /// let (mantissa, exponent, sign) = num.integer_decode();
-    /// let sign_f = sign as f32;
-    /// let mantissa_f = mantissa as f32;
-    /// let exponent_f = num.powf(exponent as f32);
-    ///
-    /// // 1 * 8388608 * 2^(-22) == 2
-    /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    /// [floating-point]: ../reference/types.html#machine-types
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    #[allow(deprecated)]
-    pub fn integer_decode(self) -> (u64, i16, i8) {
-        num::Float::integer_decode(self)
-    }
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// ```
@@ -712,89 +660,6 @@ pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
     #[inline]
     pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
 
-    /// Constructs a floating point number of `x*2^exp`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    /// // 3*2^2 - 12 == 0
-    /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn ldexp(x: f32, exp: isize) -> f32 {
-        unsafe { cmath::ldexpf(x, exp as c_int) }
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent,
-    /// satisfying:
-    ///
-    ///  * `self = x * 2^exp`
-    ///  * `0.5 <= abs(x) < 1.0`
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let x = 4.0f32;
-    ///
-    /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
-    /// let f = x.frexp();
-    /// let abs_difference_0 = (f.0 - 0.5).abs();
-    /// let abs_difference_1 = (f.1 as f32 - 3.0).abs();
-    ///
-    /// assert!(abs_difference_0 <= f32::EPSILON);
-    /// assert!(abs_difference_1 <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn frexp(self) -> (f32, isize) {
-        unsafe {
-            let mut exp = 0;
-            let x = cmath::frexpf(self, &mut exp);
-            (x, exp as isize)
-        }
-    }
-
-    /// Returns the next representable floating-point value in the direction of
-    /// `other`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let x = 1.0f32;
-    ///
-    /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs();
-    ///
-    /// assert!(abs_diff <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "unsure about its place in the world",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn next_after(self, other: f32) -> f32 {
-        unsafe { cmath::nextafterf(self, other) }
-    }
-
     /// Returns the maximum of the two numbers.
     ///
     /// ```
@@ -1462,23 +1327,6 @@ fn test_classify() {
         assert_eq!(1e-38f32.classify(), Fp::Subnormal);
     }
 
-    #[test]
-    #[allow(deprecated)]
-    fn test_integer_decode() {
-        assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
-        assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
-        assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
-        assert_eq!(0f32.integer_decode(), (0, -150, 1));
-        assert_eq!((-0f32).integer_decode(), (0, -150, -1));
-        assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1));
-        assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1));
-
-        // Ignore the "sign" (quiet / signalling flag) of NAN.
-        // It can vary between runtime operations and LLVM folding.
-        let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
-        assert_eq!((nan_m, nan_e), (12582912, 105));
-    }
-
     #[test]
     fn test_floor() {
         assert_approx_eq!(1.0f32.floor(), 1.0f32);
@@ -1790,58 +1638,6 @@ fn test_to_radians() {
         assert_eq!(neg_inf.to_radians(), neg_inf);
     }
 
-    #[test]
-    #[allow(deprecated)]
-    fn test_ldexp() {
-        let f1 = 2.0f32.powi(-123);
-        let f2 = 2.0f32.powi(-111);
-        let f3 = 1.75 * 2.0f32.powi(-12);
-        assert_eq!(f32::ldexp(1f32, -123), f1);
-        assert_eq!(f32::ldexp(1f32, -111), f2);
-        assert_eq!(f32::ldexp(1.75f32, -12), f3);
-
-        assert_eq!(f32::ldexp(0f32, -123), 0f32);
-        assert_eq!(f32::ldexp(-0f32, -123), -0f32);
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(f32::ldexp(inf, -123), inf);
-        assert_eq!(f32::ldexp(neg_inf, -123), neg_inf);
-        assert!(f32::ldexp(nan, -123).is_nan());
-    }
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_frexp() {
-        let f1 = 2.0f32.powi(-123);
-        let f2 = 2.0f32.powi(-111);
-        let f3 = 1.75 * 2.0f32.powi(-123);
-        let (x1, exp1) = f1.frexp();
-        let (x2, exp2) = f2.frexp();
-        let (x3, exp3) = f3.frexp();
-        assert_eq!((x1, exp1), (0.5f32, -122));
-        assert_eq!((x2, exp2), (0.5f32, -110));
-        assert_eq!((x3, exp3), (0.875f32, -122));
-        assert_eq!(f32::ldexp(x1, exp1), f1);
-        assert_eq!(f32::ldexp(x2, exp2), f2);
-        assert_eq!(f32::ldexp(x3, exp3), f3);
-
-        assert_eq!(0f32.frexp(), (0f32, 0));
-        assert_eq!((-0f32).frexp(), (-0f32, 0));
-    }
-
-    #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
-    #[allow(deprecated)]
-    fn test_frexp_nowin() {
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(match inf.frexp() { (x, _) => x }, inf);
-        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
-        assert!(match nan.frexp() { (x, _) => x.is_nan() })
-    }
-
     #[test]
     fn test_asinh() {
         assert_eq!(0.0f32.asinh(), 0.0f32);
index be55cb80c92fa3b9f1396ba28ba91d1a9803f9ba..82e3903eec7b13d8270b39115d3402fa7ee9a689 100644 (file)
@@ -22,8 +22,6 @@
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
 use num::FpCategory;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -188,36 +186,6 @@ pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
     #[inline]
     pub fn classify(self) -> FpCategory { num::Float::classify(self) }
 
-    /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
-    /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
-    /// The floating point encoding is documented in the [Reference][floating-point].
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let num = 2.0f64;
-    ///
-    /// // (8388608, -22, 1)
-    /// let (mantissa, exponent, sign) = num.integer_decode();
-    /// let sign_f = sign as f64;
-    /// let mantissa_f = mantissa as f64;
-    /// let exponent_f = num.powf(exponent as f64);
-    ///
-    /// // 1 * 8388608 * 2^(-22) == 2
-    /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    /// [floating-point]: ../reference/types.html#machine-types
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    #[allow(deprecated)]
-    pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) }
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// ```
@@ -606,84 +574,6 @@ pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) }
     #[inline]
     pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
 
-    /// Constructs a floating point number of `x*2^exp`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// // 3*2^2 - 12 == 0
-    /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn ldexp(x: f64, exp: isize) -> f64 {
-        unsafe { cmath::ldexp(x, exp as c_int) }
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent,
-    /// satisfying:
-    ///
-    ///  * `self = x * 2^exp`
-    ///  * `0.5 <= abs(x) < 1.0`
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let x = 4.0_f64;
-    ///
-    /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
-    /// let f = x.frexp();
-    /// let abs_difference_0 = (f.0 - 0.5).abs();
-    /// let abs_difference_1 = (f.1 as f64 - 3.0).abs();
-    ///
-    /// assert!(abs_difference_0 < 1e-10);
-    /// assert!(abs_difference_1 < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn frexp(self) -> (f64, isize) {
-        unsafe {
-            let mut exp = 0;
-            let x = cmath::frexp(self, &mut exp);
-            (x, exp as isize)
-        }
-    }
-
-    /// Returns the next representable floating-point value in the direction of
-    /// `other`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let x = 1.0f64;
-    ///
-    /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs();
-    ///
-    /// assert!(abs_diff < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "unsure about its place in the world",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn next_after(self, other: f64) -> f64 {
-        unsafe { cmath::nextafter(self, other) }
-    }
-
     /// Returns the maximum of the two numbers.
     ///
     /// ```
@@ -1353,23 +1243,6 @@ fn test_classify() {
         assert_eq!(1e-308f64.classify(), Fp::Subnormal);
     }
 
-    #[test]
-    #[allow(deprecated)]
-    fn test_integer_decode() {
-        assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
-        assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
-        assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
-        assert_eq!(0f64.integer_decode(), (0, -1075, 1));
-        assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
-        assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1));
-        assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
-
-        // Ignore the "sign" (quiet / signalling flag) of NAN.
-        // It can vary between runtime operations and LLVM folding.
-        let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
-        assert_eq!((nan_m, nan_e), (6755399441055744, 972));
-    }
-
     #[test]
     fn test_floor() {
         assert_approx_eq!(1.0f64.floor(), 1.0f64);
@@ -1681,58 +1554,6 @@ fn test_to_radians() {
         assert_eq!(neg_inf.to_radians(), neg_inf);
     }
 
-    #[test]
-    #[allow(deprecated)]
-    fn test_ldexp() {
-        let f1 = 2.0f64.powi(-123);
-        let f2 = 2.0f64.powi(-111);
-        let f3 = 1.75 * 2.0f64.powi(-12);
-        assert_eq!(f64::ldexp(1f64, -123), f1);
-        assert_eq!(f64::ldexp(1f64, -111), f2);
-        assert_eq!(f64::ldexp(1.75f64, -12), f3);
-
-        assert_eq!(f64::ldexp(0f64, -123), 0f64);
-        assert_eq!(f64::ldexp(-0f64, -123), -0f64);
-
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
-        assert_eq!(f64::ldexp(inf, -123), inf);
-        assert_eq!(f64::ldexp(neg_inf, -123), neg_inf);
-        assert!(f64::ldexp(nan, -123).is_nan());
-    }
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_frexp() {
-        let f1 = 2.0f64.powi(-123);
-        let f2 = 2.0f64.powi(-111);
-        let f3 = 1.75 * 2.0f64.powi(-123);
-        let (x1, exp1) = f1.frexp();
-        let (x2, exp2) = f2.frexp();
-        let (x3, exp3) = f3.frexp();
-        assert_eq!((x1, exp1), (0.5f64, -122));
-        assert_eq!((x2, exp2), (0.5f64, -110));
-        assert_eq!((x3, exp3), (0.875f64, -122));
-        assert_eq!(f64::ldexp(x1, exp1), f1);
-        assert_eq!(f64::ldexp(x2, exp2), f2);
-        assert_eq!(f64::ldexp(x3, exp3), f3);
-
-        assert_eq!(0f64.frexp(), (0f64, 0));
-        assert_eq!((-0f64).frexp(), (-0f64, 0));
-    }
-
-    #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
-    #[allow(deprecated)]
-    fn test_frexp_nowin() {
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
-        assert_eq!(match inf.frexp() { (x, _) => x }, inf);
-        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
-        assert!(match nan.frexp() { (x, _) => x.is_nan() })
-    }
-
     #[test]
     fn test_asinh() {
         assert_eq!(0.0f64.asinh(), 0.0f64);
index cd096c115ba5a2a181f9a2275076915240bbaf13..e2832873e2e674a83d2e80d67503fd2ff83471ce 100644 (file)
@@ -466,6 +466,9 @@ pub trait Read {
     /// variant will be returned. If an error is returned then it must be
     /// guaranteed that no bytes were read.
     ///
+    /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the read
+    /// operation should be retried if there is nothing else to do.
+    ///
     /// # Examples
     ///
     /// [`File`][file]s implement `Read`:
@@ -481,7 +484,7 @@ pub trait Read {
     /// let mut f = File::open("foo.txt")?;
     /// let mut buffer = [0; 10];
     ///
-    /// // read 10 bytes
+    /// // read up to 10 bytes
     /// f.read(&mut buffer[..])?;
     /// # Ok(())
     /// # }
@@ -885,6 +888,9 @@ pub trait Write {
     /// It is **not** considered an error if the entire buffer could not be
     /// written to this writer.
     ///
+    /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the
+    /// write operation should be retried if there is nothing else to do.
+    ///
     /// # Examples
     ///
     /// ```
@@ -894,6 +900,7 @@ pub trait Write {
     /// # fn foo() -> std::io::Result<()> {
     /// let mut buffer = File::create("foo.txt")?;
     ///
+    /// // Writes some prefix of the byte string, not necessarily all of it.
     /// buffer.write(b"some bytes")?;
     /// # Ok(())
     /// # }
@@ -929,14 +936,17 @@ pub trait Write {
 
     /// Attempts to write an entire buffer into this write.
     ///
-    /// This method will continuously call `write` while there is more data to
-    /// write. This method will not return until the entire buffer has been
-    /// successfully written or an error occurs. The first error generated from
-    /// this method will be returned.
+    /// This method will continuously call `write` until there is no more data
+    /// to be written or an error of non-`ErrorKind::Interrupted` kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of `ErrorKind::Interrupted` kind generated from this method will be
+    /// returned.
     ///
     /// # Errors
     ///
-    /// This function will return the first error that `write` returns.
+    /// This function will return the first error of
+    /// non-`ErrorKind::Interrupted` kind that `write` returns.
     ///
     /// # Examples
     ///
@@ -1494,6 +1504,87 @@ pub struct Chain<T, U> {
     done_first: bool,
 }
 
+impl<T, U> Chain<T, U> {
+    /// Consumes the `Chain`, returning the wrapped readers.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(more_io_inner_methods)]
+    ///
+    /// # use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> io::Result<()> {
+    /// let mut foo_file = File::open("foo.txt")?;
+    /// let mut bar_file = File::open("bar.txt")?;
+    ///
+    /// let chain = foo_file.chain(bar_file);
+    /// let (foo_file, bar_file) = chain.into_inner();
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "more_io_inner_methods", issue="41519")]
+    pub fn into_inner(self) -> (T, U) {
+        (self.first, self.second)
+    }
+
+    /// Gets references to the underlying readers in this `Chain`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(more_io_inner_methods)]
+    ///
+    /// # use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> io::Result<()> {
+    /// let mut foo_file = File::open("foo.txt")?;
+    /// let mut bar_file = File::open("bar.txt")?;
+    ///
+    /// let chain = foo_file.chain(bar_file);
+    /// let (foo_file, bar_file) = chain.get_ref();
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "more_io_inner_methods", issue="41519")]
+    pub fn get_ref(&self) -> (&T, &U) {
+        (&self.first, &self.second)
+    }
+
+    /// Gets mutable references to the underlying readers in this `Chain`.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying readers as doing so may corrupt the internal state of this
+    /// `Chain`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(more_io_inner_methods)]
+    ///
+    /// # use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> io::Result<()> {
+    /// let mut foo_file = File::open("foo.txt")?;
+    /// let mut bar_file = File::open("bar.txt")?;
+    ///
+    /// let mut chain = foo_file.chain(bar_file);
+    /// let (foo_file, bar_file) = chain.get_mut();
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "more_io_inner_methods", issue="41519")]
+    pub fn get_mut(&mut self) -> (&mut T, &mut U) {
+        (&mut self.first, &mut self.second)
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1606,6 +1697,64 @@ pub fn limit(&self) -> u64 { self.limit }
     pub fn into_inner(self) -> T {
         self.inner
     }
+
+    /// Gets a reference to the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(more_io_inner_methods)]
+    ///
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> io::Result<()> {
+    /// let mut file = File::open("foo.txt")?;
+    ///
+    /// let mut buffer = [0; 5];
+    /// let mut handle = file.take(5);
+    /// handle.read(&mut buffer)?;
+    ///
+    /// let file = handle.get_ref();
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "more_io_inner_methods", issue="41519")]
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying reader as doing so may corrupt the internal limit of this
+    /// `Take`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(more_io_inner_methods)]
+    ///
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// # fn foo() -> io::Result<()> {
+    /// let mut file = File::open("foo.txt")?;
+    ///
+    /// let mut buffer = [0; 5];
+    /// let mut handle = file.take(5);
+    /// handle.read(&mut buffer)?;
+    ///
+    /// let file = handle.get_mut();
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "more_io_inner_methods", issue="41519")]
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 367779bb701c858f95f29fc28d39c510962f33e6..70225da5f3355c2150b722b4a3bdc20f15deaa7d 100644 (file)
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_consts)]
-#![feature(borrow_state)]
 #![feature(box_syntax)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
-#![feature(float_extras)]
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
 #![feature(fnbox)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(vec_push_all)]
-#![feature(zero_one)]
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(stage0, feature(pub_restricted))]
 #![cfg_attr(test, feature(float_bits_conv))]
index 5f83d077a13682897b570234ca23ae77b10520c1..ff89887ac92c3c59369a75ffcf5e9df20d3f224e 100644 (file)
@@ -16,9 +16,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use core::num::{Zero, One};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError};
 #[stable(feature = "rust1", since = "1.0.0")]
index 5e473a933a67671c8374ed7b79fe8c3a72a78422..60ad8fcc54ccd6af6eec6072f78ba811072d4575 100644 (file)
@@ -165,3 +165,66 @@ pub struct stat {
     }
 }
 
+#[cfg(target_arch = "x86_64")]
+mod arch {
+    use os::raw::{c_uint, c_long, c_ulong};
+    use os::unix::raw::{uid_t, gid_t};
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type dev_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type mode_t = u32;
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = u32;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = i64;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: dev_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: ino_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: c_uint,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: uid_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: gid_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: dev_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_ulong,
+        __unused: [c_long; 3],
+    }
+}
+
index 812b65b61e7f0a9a2af511e4ad90d32bb7cec218..9d66430bc93032a59bf5953027646bd9730bc07a 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Cross-platform path manipulation.
 //!
-//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`]
+//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`]
 //! and [`str`]), for working with paths abstractly. These types are thin wrappers
 //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly
 //! on strings according to the local platform's path syntax.
@@ -1189,8 +1189,13 @@ pub fn pop(&mut self) -> bool {
     /// If [`self.file_name`] was [`None`], this is equivalent to pushing
     /// `file_name`.
     ///
+    /// Otherwise it is equivalent to calling [`pop`] and then pushing
+    /// `file_name`. The new path will be a sibling of the original path.
+    /// (That is, it will have the same parent.)
+    ///
     /// [`self.file_name`]: struct.PathBuf.html#method.file_name
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`pop`]: struct.PathBuf.html#method.pop
     ///
     /// # Examples
     ///
@@ -1725,7 +1730,10 @@ pub fn parent(&self) -> Option<&Path> {
         })
     }
 
-    /// Returns the final component of the `Path`, if it is a normal file.
+    /// Returns the final component of the `Path`, if there is one.
+    ///
+    /// If the path is a normal file, this is the file name. If it's the path of a directory, this
+    /// is the directory name.
     ///
     /// Returns [`None`] If the path terminates in `..`.
     ///
@@ -1737,10 +1745,12 @@ pub fn parent(&self) -> Option<&Path> {
     /// use std::path::Path;
     /// use std::ffi::OsStr;
     ///
-    /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name());
+    /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
+    /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
     /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
     /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
     /// assert_eq!(None, Path::new("foo.txt/..").file_name());
+    /// assert_eq!(None, Path::new("/").file_name());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn file_name(&self) -> Option<&OsStr> {
@@ -1926,6 +1936,9 @@ fn _join(&self, path: &Path) -> PathBuf {
     ///
     /// let path = Path::new("/tmp/foo.txt");
     /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
+    ///
+    /// let path = Path::new("/tmp");
+    /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
index 3795c42f5efa12aa2f3b086b586f9a058fbb1aec..4ec9076de61665766314c1e84b586836f6d714d5 100644 (file)
 /// spawning process and can itself be constructed using a builder-style
 /// interface.
 ///
+/// There is no implementation of [`Drop`] for child processes,
+/// so if you do not ensure the `Child` has exited then it will continue to
+/// run, even after the `Child` handle to the child process has gone out of
+/// scope.
+///
+/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make
+/// the parent process wait until the child has actually exited before
+/// continuing.
+///
 /// # Examples
 ///
 /// ```should_panic
 /// assert!(ecode.success());
 /// ```
 ///
-/// # Note
-///
-/// Take note that there is no implementation of [`Drop`] for child processes,
-/// so if you do not ensure the `Child` has exited then it will continue to
-/// run, even after the `Child` handle to the child process has gone out of
-/// scope.
-///
-/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make
-/// the parent process wait until the child has actually exited before
-/// continuing.
-///
 /// [`Command`]: struct.Command.html
 /// [`Drop`]: ../../core/ops/trait.Drop.html
 /// [`wait`]: #method.wait
index 852675edc0238d60baa13047c9bc6df67acbc402..6c8839224f77dafb5f00f039ec22b18a09f50d5c 100644 (file)
@@ -452,7 +452,7 @@ impl<T> !Sync for SyncSender<T> {}
 /// An error returned from the [`recv`] function on a [`Receiver`].
 ///
 /// The [`recv`] operation can only fail if the sending half of a
-/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further
 /// messages will ever be received.
 ///
 /// [`recv`]: struct.Receiver.html#method.recv
index a08cec38f732dae6ed8c8da0009080f91d08399d..a1ad94872de5c1ae366dee9d9fe84c1eeaf89259 100644 (file)
@@ -157,7 +157,7 @@ pub fn add_duration(&self, other: &Duration) -> Instant {
         pub fn sub_duration(&self, other: &Duration) -> Instant {
             Instant {
                 t: self.t.checked_sub(dur2intervals(other))
-                       .expect("overflow when adding duration to instant"),
+                       .expect("overflow when subtracting duration from instant"),
             }
         }
     }
index 6f5f52ff1e953fa4b5798d90df7be07a434ddca3..82492d976276e05d6ed6d758872c48acc17405ee 100644 (file)
@@ -147,6 +147,24 @@ pub fn value_str(&self) -> Option<Symbol> {
         self.meta_item().and_then(|meta_item| meta_item.value_str())
     }
 
+    /// Returns a name and single literal value tuple of the MetaItem.
+    pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
+        self.meta_item().and_then(
+            |meta_item| meta_item.meta_item_list().and_then(
+                |meta_item_list| {
+                    if meta_item_list.len() == 1 {
+                        let nested_item = &meta_item_list[0];
+                        if nested_item.is_literal() {
+                            Some((meta_item.name(), nested_item.literal().unwrap()))
+                        } else {
+                            None
+                        }
+                    }
+                    else {
+                        None
+                    }}))
+    }
+
     /// Returns a MetaItem if self is a MetaItem with Kind Word.
     pub fn word(&self) -> Option<&MetaItem> {
         self.meta_item().and_then(|meta_item| if meta_item.is_word() {
@@ -931,6 +949,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                     continue
                 }
 
+                let mut recognised = false;
                 if let Some(mi) = item.word() {
                     let word = &*mi.name().as_str();
                     let hint = match word {
@@ -941,20 +960,43 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                         _ => match int_type_of_word(word) {
                             Some(ity) => Some(ReprInt(ity)),
                             None => {
-                                // Not a word we recognize
-                                span_err!(diagnostic, item.span, E0552,
-                                          "unrecognized representation hint");
                                 None
                             }
                         }
                     };
 
                     if let Some(h) = hint {
+                        recognised = true;
                         acc.push(h);
                     }
-                } else {
-                    span_err!(diagnostic, item.span, E0553,
-                              "unrecognized enum representation hint");
+                } else if let Some((name, value)) = item.name_value_literal() {
+                    if name == "align" {
+                        recognised = true;
+                        let mut align_error = None;
+                        if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
+                            if align.is_power_of_two() {
+                                // rustc::ty::layout::Align restricts align to <= 32768
+                                if align <= 32768 {
+                                    acc.push(ReprAlign(align as u16));
+                                } else {
+                                    align_error = Some("larger than 32768");
+                                }
+                            } else {
+                                align_error = Some("not a power of two");
+                            }
+                        } else {
+                            align_error = Some("not an unsuffixed integer");
+                        }
+                        if let Some(align_error) = align_error {
+                            span_err!(diagnostic, item.span, E0589,
+                                      "invalid `repr(align)` attribute: {}", align_error);
+                        }
+                    }
+                }
+                if !recognised {
+                    // Not a word we recognize
+                    span_err!(diagnostic, item.span, E0552,
+                              "unrecognized representation hint");
                 }
             }
         }
@@ -986,6 +1028,7 @@ pub enum ReprAttr {
     ReprExtern,
     ReprPacked,
     ReprSimd,
+    ReprAlign(u16),
 }
 
 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
index 2d59051ec4a537465b80ae6d9448054b4142a696..01d1277ea6265014c018401a8854033db84931fa 100644 (file)
@@ -287,10 +287,10 @@ fn foo() {}
     E0550, // multiple deprecated attributes
     E0551, // incorrect meta item
     E0552, // unrecognized representation hint
-    E0553, // unrecognized enum representation hint
     E0554, // #[feature] may not be used on the [] release channel
     E0555, // malformed feature attribute, expected #![feature(...)]
     E0556, // malformed feature, expected just one word
     E0557, // feature has been removed
     E0584, // file for module `..` found at both .. and ..
+    E0589, // invalid `repr(align)` attribute
 }
index 680bd7599ace06e9baf4eedd9568e2e8cbc3c03b..842398ea02b9e132f5b4445c2bce05f8797a031d 100644 (file)
@@ -205,6 +205,8 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         module.directory.pop();
         self.cx.current_expansion.module = Rc::new(module);
 
+        let orig_mod_span = krate.module.inner;
+
         let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
             attrs: krate.attrs,
             span: krate.span,
@@ -214,11 +216,19 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
             vis: ast::Visibility::Public,
         })));
 
-        match self.expand(krate_item).make_items().pop().unwrap().unwrap() {
-            ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => {
+        match self.expand(krate_item).make_items().pop().map(P::unwrap) {
+            Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
                 krate.attrs = attrs;
                 krate.module = module;
             },
+            None => {
+                // Resolution failed so we return an empty expansion
+                krate.attrs = vec![];
+                krate.module = ast::Mod {
+                    inner: orig_mod_span,
+                    items: vec![],
+                };
+            },
             _ => unreachable!(),
         };
 
index 175447e11127058121478dd6a5b0208c0dbbad1a..9b55a860b3595a0e4edd1bfb5e837d22f71ee7fd 100644 (file)
@@ -338,6 +338,9 @@ pub fn new() -> Features {
     // Allows the `catch {...}` expression
     (active, catch_expr, "1.17.0", Some(31436)),
 
+    // Allows `repr(align(u16))` struct attribute (RFC 1358)
+    (active, repr_align, "1.17.0", Some(33626)),
+
     // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
     (active, rvalue_static_promotion, "1.15.1", Some(38865)),
 
@@ -1189,6 +1192,11 @@ fn visit_item(&mut self, i: &'a ast::Item) {
                                                     and possibly buggy");
 
                             }
+                            if item.check_name("align") {
+                                gate_feature_post!(&self, repr_align, i.span,
+                                                   "the struct `#[repr(align(u16))]` attribute \
+                                                    is experimental");
+                            }
                         }
                     }
                 }
index 0cdb09a842f4651d1f5d35ef0cfe909b6789f3b6..1baf0d1b54ce1f7530dd6ab9736134be4661c80d 100644 (file)
@@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
 enum PrevTokenKind {
     DocComment,
     Comma,
+    Plus,
     Interpolated,
     Eof,
     Other,
@@ -1061,6 +1062,7 @@ pub fn bump(&mut self) {
         self.prev_token_kind = match self.token {
             token::DocComment(..) => PrevTokenKind::DocComment,
             token::Comma => PrevTokenKind::Comma,
+            token::BinOp(token::Plus) => PrevTokenKind::Plus,
             token::Interpolated(..) => PrevTokenKind::Interpolated,
             token::Eof => PrevTokenKind::Eof,
             _ => PrevTokenKind::Other,
@@ -1354,20 +1356,26 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
                     break;
                 }
             }
+            let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus;
             self.expect(&token::CloseDelim(token::Paren))?;
 
             if ts.len() == 1 && !last_comma {
                 let ty = ts.into_iter().nth(0).unwrap().unwrap();
+                let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus);
                 match ty.node {
-                    // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318).
-                    TyKind::Path(None, ref path)
-                            if allow_plus && self.token == token::BinOp(token::Plus) => {
-                        self.bump(); // `+`
-                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span));
-                        let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)];
-                        bounds.append(&mut self.parse_ty_param_bounds()?);
-                        TyKind::TraitObject(bounds)
+                    // `(TY_BOUND_NOPAREN) + BOUND + ...`.
+                    TyKind::Path(None, ref path) if maybe_bounds => {
+                        self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
                     }
+                    TyKind::TraitObject(ref bounds)
+                            if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
+                        let path = match bounds[0] {
+                            TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
+                            _ => self.bug("unexpected lifetime bound"),
+                        };
+                        self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+                    }
+                    // `(TYPE)`
                     _ => TyKind::Paren(P(ty))
                 }
             } else {
@@ -1418,11 +1426,8 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
                 //   `Trait1 + Trait2 + 'a`
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span));
-                    let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                    bounds.append(&mut self.parse_ty_param_bounds()?);
-                    TyKind::TraitObject(bounds)
+                if allow_plus && self.check(&token::BinOp(token::Plus)) {
+                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
                 } else {
                     TyKind::Path(None, path)
                 }
@@ -1440,12 +1445,8 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    bounds.append(&mut self.parse_ty_param_bounds()?)
-                }
-                TyKind::TraitObject(bounds)
+                let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus));
+                self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
             }
         } else if self.eat_keyword(keywords::Impl) {
             // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
@@ -1468,6 +1469,17 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
         Ok(P(ty))
     }
 
+    fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast::Path,
+                              lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
+        let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)];
+        if parse_plus {
+            self.bump(); // `+`
+            bounds.append(&mut self.parse_ty_param_bounds()?);
+        }
+        Ok(TyKind::TraitObject(bounds))
+    }
+
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
         if !allow_plus || self.token != token::BinOp(token::Plus) {
@@ -4070,28 +4082,43 @@ fn warn_missing_semicolon(&self) {
     // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
     // BOUND = TY_BOUND | LT_BOUND
     // LT_BOUND = LIFETIME (e.g. `'a`)
-    // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
+    // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
+    // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
     fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
         let mut bounds = Vec::new();
         loop {
-            let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
-            if self.check_lifetime() {
-                if let Some(question_span) = question {
-                    self.span_err(question_span,
-                                  "`?` may only modify trait bounds, not lifetime bounds");
-                }
-                bounds.push(RegionTyParamBound(self.expect_lifetime()));
-            } else if self.check_keyword(keywords::For) || self.check_path() {
-                let lo = self.span;
-                let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-                let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let modifier = if question.is_some() {
-                    TraitBoundModifier::Maybe
+            let is_bound_start = self.check_path() || self.check_lifetime() ||
+                                 self.check(&token::Question) ||
+                                 self.check_keyword(keywords::For) ||
+                                 self.check(&token::OpenDelim(token::Paren));
+            if is_bound_start {
+                let has_parens = self.eat(&token::OpenDelim(token::Paren));
+                let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
+                if self.token.is_lifetime() {
+                    if let Some(question_span) = question {
+                        self.span_err(question_span,
+                                      "`?` may only modify trait bounds, not lifetime bounds");
+                    }
+                    bounds.push(RegionTyParamBound(self.expect_lifetime()));
                 } else {
-                    TraitBoundModifier::None
-                };
-                bounds.push(TraitTyParamBound(poly_trait, modifier));
+                    let lo = self.span;
+                    let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+                    let path = self.parse_path(PathStyle::Type)?;
+                    let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+                    let modifier = if question.is_some() {
+                        TraitBoundModifier::Maybe
+                    } else {
+                        TraitBoundModifier::None
+                    };
+                    bounds.push(TraitTyParamBound(poly_trait, modifier));
+                }
+                if has_parens {
+                    self.expect(&token::CloseDelim(token::Paren))?;
+                    if let Some(&RegionTyParamBound(..)) = bounds.last() {
+                        self.span_err(self.prev_span,
+                                      "parenthesized lifetime bounds are not supported");
+                    }
+                }
             } else {
                 break
             }
index a74f59b004bb76116ef75f4789f9bb4df58dcfca..dc9b22c37e28b5c14a32c1a5d58b5eff5f176bb2 100644 (file)
@@ -128,9 +128,9 @@ fn foo() {
  --> test.rs:2:10
   |
 2 |   fn foo() {
-  |  __________^ starting here...
+  |  __________^
 3 | | }
-  | |_^ ...ending here: test
+  | |_^ test
 
 "#);
 }
@@ -161,11 +161,11 @@ fn foo() {
  --> test.rs:2:10
   |
 2 |   fn foo() {
-  |  __________^ starting here...
+  |  __________^
 3 | |
 4 | |
 5 | |   }
-  | |___^ ...ending here: test
+  | |___^ test
 
 "#);
 }
@@ -207,14 +207,14 @@ fn foo() {
  --> test.rs:3:3
   |
 3 |      X0 Y0
-  |  ____^__- starting here...
+  |  ____^__-
   | | ___|
-  | ||   starting here...
+  | ||
 4 | ||   X1 Y1
 5 | ||   X2 Y2
-  | ||____^__- ...ending here: `Y` is a good letter too
+  | ||____^__- `Y` is a good letter too
   |  |____|
-  |       ...ending here: `X` is a good letter
+  |       `X` is a good letter
 
 "#);
 }
@@ -256,13 +256,13 @@ fn foo() {
  --> test.rs:3:3
   |
 3 |      X0 Y0
-  |  ____^__- starting here...
+  |  ____^__-
   | | ___|
-  | ||   starting here...
+  | ||
 4 | ||   Y1 X1
-  | ||____-__^ ...ending here: `X` is a good letter
+  | ||____-__^ `X` is a good letter
   | |_____|
-  |       ...ending here: `Y` is a good letter too
+  |       `Y` is a good letter too
 
 "#);
 }
@@ -306,13 +306,13 @@ fn foo() {
  --> test.rs:3:6
   |
 3 |      X0 Y0 Z0
-  |   ______^ starting here...
+  |   ______^
 4 |  |   X1 Y1 Z1
-  |  |_________- starting here...
+  |  |_________-
 5 | ||   X2 Y2 Z2
-  | ||____^ ...ending here: `X` is a good letter
+  | ||____^ `X` is a good letter
 6 | |    X3 Y3 Z3
-  | |_____- ...ending here: `Y` is a good letter too
+  | |_____- `Y` is a good letter too
 
 "#);
 }
@@ -366,16 +366,16 @@ fn foo() {
  --> test.rs:3:3
   |
 3 |       X0 Y0 Z0
-  |  _____^__-__- starting here...
+  |  _____^__-__-
   | | ____|__|
-  | || ___|  starting here...
-  | |||   starting here...
+  | || ___|
+  | |||
 4 | |||   X1 Y1 Z1
 5 | |||   X2 Y2 Z2
-  | |||____^__-__- ...ending here: `Z` label
+  | |||____^__-__- `Z` label
   |  ||____|__|
-  |   |____|  ...ending here: `Y` is a good letter too
-  |        ...ending here: `X` is a good letter
+  |   |____|  `Y` is a good letter too
+  |        `X` is a good letter
 
 "#);
 }
@@ -430,17 +430,17 @@ fn foo() {
  --> test.rs:3:6
   |
 3 |      X0 Y0 Z0
-  |   ______^ starting here...
+  |   ______^
 4 |  |   X1 Y1 Z1
-  |  |____^_- starting here...
+  |  |____^_-
   | ||____|
-  | |     ...ending here: `X` is a good letter
+  | |     `X` is a good letter
 5 | |    X2 Y2 Z2
-  | |____-______- ...ending here: `Y` is a good letter too
+  | |____-______- `Y` is a good letter too
   |  ____|
-  | |    starting here...
+  | |
 6 | |    X3 Y3 Z3
-  | |________- ...ending here: `Z`
+  | |________- `Z`
 
 "#);
 }
@@ -458,7 +458,7 @@ fn foo() {
     vec![
         SpanLabel {
             start: Position {
-                string: "Y0",
+                string: "X0",
                 count: 1,
             },
             end: Position {
@@ -481,16 +481,15 @@ fn foo() {
     ],
     r#"
 error: foo
- --> test.rs:3:6
+ --> test.rs:3:3
   |
-3 |     X0 Y0 Z0
-  |  ______^ starting here...
+3 | /   X0 Y0 Z0
 4 | |   X1 Y1 Z1
-  | |____^ ...ending here: `X` is a good letter
+  | |____^ `X` is a good letter
 5 |     X2 Y2 Z2
-  |  ______- starting here...
+  |  ______-
 6 | |   X3 Y3 Z3
-  | |__________- ...ending here: `Y` is a good letter too
+  | |__________- `Y` is a good letter too
 
 "#);
 }
@@ -534,14 +533,14 @@ fn foo() {
  --> test.rs:3:6
   |
 3 |      X0 Y0 Z0
-  |   ______^ starting here...
+  |   ______^
 4 |  |   X1 Y1 Z1
-  |  |____^____- starting here...
+  |  |____^____-
   | ||____|
-  | |     ...ending here: `X` is a good letter
+  | |     `X` is a good letter
 5 | |    X2 Y2 Z2
 6 | |    X3 Y3 Z3
-  | |___________- ...ending here: `Y` is a good letter too
+  | |___________- `Y` is a good letter too
 
 "#);
 }
@@ -982,18 +981,18 @@ fn foo() {
   --> test.rs:3:6
    |
 3  |      X0 Y0 Z0
-   |   ______^ starting here...
+   |   ______^
 4  |  |   X1 Y1 Z1
-   |  |____^____- starting here...
+   |  |____^____-
    | ||____|
-   | |     ...ending here: `X` is a good letter
+   | |     `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
+   | |___________- `Y` is a good letter too
 
 "#);
 }
@@ -1047,21 +1046,21 @@ fn 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
+   | ||__________- `Z` is a good letter too
 ...   |
 15 |  | 10
 16 |  |   X3 Y3 Z3
-   |  |_______^ ...ending here: `Y` is a good letter
+   |  |_______^ `Y` is a good letter
 
 "#);
 }
index 1ff0fec1c96a6c70959d6bddf2b75942cb00718f..e96883c26f33a1c854996e89ecbdc39d1cb78655 100644 (file)
@@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
     for a in type_attrs {
         for r in &attr::find_repr_attrs(diagnostic, a) {
             repr_type_name = match *r {
-                attr::ReprPacked | attr::ReprSimd => continue,
+                attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue,
                 attr::ReprExtern => "i32",
 
                 attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
index 2e951c3ae354bcbd2e50b30798e232949a926b75..a884d21cc5f0b23a1693d1e872fd8998a4fdd17f 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 2e951c3ae354bcbd2e50b30798e232949a926b75
+Subproject commit a884d21cc5f0b23a1693d1e872fd8998a4fdd17f
index 65c85697ce720f6842a2fd52d6bb70626ac98d71..e8b92aab1da1e556f2518b9f7aac050ace6cd928 100644 (file)
@@ -22,7 +22,7 @@
 // object (usually called `crtX.o), which then invokes initialization callbacks
 // of other runtime components (registered via yet another special image section).
 
-#![feature(no_core, lang_items)]
+#![feature(no_core, lang_items, optin_builtin_traits)]
 #![crate_type="rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
 trait Sized {}
 #[lang = "sync"]
 trait Sync {}
+impl Sync for .. {}
 #[lang = "copy"]
 trait Copy {}
-impl<T> Sync for T {}
+#[cfg_attr(not(stage0), lang = "freeze")]
+trait Freeze {}
+impl Freeze for .. {}
 
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
 pub mod eh_frames {
index a4bd5cf2c158e3d3dcd6de4a36ede21ce28cb5d3..d7e2cb6d9a50ba6c8e3fafe8034b62e7442d2569 100644 (file)
@@ -36,7 +36,7 @@ pub fn droppy() {
 // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
+// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName
 // The next line checks for the } that ends the function definition
 // CHECK-LABEL: {{^[}]}}
index e0de64b26df471fe857689099f1e9d62d94a91df..9fd600b32e6c71c6473d4c9878c43615a8f2483e 100644 (file)
@@ -37,5 +37,6 @@ pub fn test() {
     // CHECK: bitcast{{.*}}personalityslot
     // CHECK-NEXT: call void @llvm.lifetime.start
     might_unwind();
+    let _t = S;
     might_unwind();
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs
new file mode 100644 (file)
index 0000000..99400bd
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
new file mode 100644 (file)
index 0000000..1723791
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// aux-build:issue-41211.rs
+
+// FIXME: https://github.com/rust-lang/rust/issues/41430
+// This is a temporary regression test for the ICE reported in #41211
+
+#![feature(proc_macro)]
+#![emit_unchanged]
+//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope
+extern crate issue_41211;
+use issue_41211::emit_unchanged;
+
+fn main() {}
index b07d3e2f9067597ffa9f508df7b9c712bf364817..c0bfd3690c8598fd3b5989aaea5102f6afcca4c8 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![allow(dead_code)]
+#![feature(attr_literals)]
 #![feature(repr_simd)]
 
 #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
@@ -29,6 +30,9 @@ fn f() {}
 #[repr(C)]
 enum EExtern { A, B }
 
+#[repr(align(8))] //~ ERROR: attribute should be applied to struct
+enum EAlign { A, B }
+
 #[repr(packed)] //~ ERROR: attribute should be applied to struct
 enum EPacked { A, B }
 
index 6b468ff96620d25bf0b667d9823d4ba70b5dc964..7c5a4e0c3c6f644467c7117cbdc8da80dcfd1d61 100644 (file)
@@ -14,6 +14,5 @@ fn main() {
     let _: &[i32] = [0];
     //~^ ERROR mismatched types
     //~| expected type `&[i32]`
-    //~| found type `[{integer}; 1]`
     //~| expected &[i32], found array of 1 elements
 }
index 9e0c0d845ca24a10d6fb06a62fd7b897ea4b8997..01fa3ffbaa6ae7a82a9f9644ccba0209b4ee4f77 100644 (file)
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
 #![allow(dead_code)]
+#![feature(attr_literals)]
+#![feature(repr_align)]
 
 #[repr(C)]
 enum A { A }
@@ -26,5 +27,7 @@ enum D { D }
 #[repr(C, packed)]
 struct E(i32);
 
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+#[repr(packed, align(8))] //~ ERROR conflicting packed and align representation hints
+struct F(i32);
+
+fn main() {}
index ff83dd004a257ccb2a9f9b76911bf796d89bd844..0745ac02d0723e620e82856f217cf666e1a21175 100644 (file)
@@ -17,6 +17,4 @@ fn f(x: usize) -> usize {
 fn main() {
     let _ = [0; f(2)];
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant expression
 }
index b40aa2a8e27dcdf67c250265c17081355c165dcc..71cac3edbc188beb9542952db26707d3d81c05d0 100644 (file)
 
 #![feature(const_fn)]
 
+#[derive(PartialEq, Eq)]
 enum Cake {
     BlackForest,
     Marmor,
 }
 use Cake::*;
 
-const BOO: (Cake, Cake) = (Marmor, BlackForest);
+struct Pair<A, B>(A, B);
+
+const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
 //~^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: enum variants
+//~| unimplemented constant expression: tuple struct constructors
 const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
     Marmor
-        //~^ ERROR: constant evaluation error [E0080]
-        //~| unimplemented constant expression: enum variants
 }
 
 const WORKS: Cake = Marmor;
@@ -34,7 +35,7 @@ const fn foo() -> Cake {
 fn main() {
     match BlackForest {
         FOO => println!("hi"), //~ NOTE: for pattern here
-        GOO => println!("meh"), //~ NOTE: for pattern here
+        GOO => println!("meh"),
         WORKS => println!("möp"),
         _ => println!("bye"),
     }
index e5afccb9cf3943080ae12feb22ce6675f4ccced6..847a82c082651f1a4550cc7bfc34aefa873f2fa3 100644 (file)
@@ -17,7 +17,7 @@ impl Trait for Foo {}
 
 pub fn main() {
     let x: Box<Trait> = Box::new(Foo);
-    let _y: &Trait = x; //~  ERROR mismatched types
+    let _y: &Trait = x; //~ ERROR E0308
                         //~| expected type `&Trait`
                         //~| found type `std::boxed::Box<Trait>`
 }
diff --git a/src/test/compile-fail/feature-gate-repr_align.rs b/src/test/compile-fail/feature-gate-repr_align.rs
new file mode 100644 (file)
index 0000000..8e986e1
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+#![feature(attr_literals)]
+
+#[repr(align(64))]
+struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental
+
+fn main() {}
index f78786a2889dab5df60ce1d813fef94b1f00b6b8..1e444a6bebf9b23b573465a7090f60b174d52fa3 100644 (file)
@@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
 fn main() {
     let mut c = for_stdin();
     let mut v = Vec::new();
-    c.read_to(v); //~ ERROR mismatched types
+    c.read_to(v); //~ ERROR E0308
 }
index 408c6d411de9030efb4b80371f4ee13cd1e5a2de..ed1634441498be40d5a05f98c51f2c5b8019a02c 100644 (file)
@@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
 fn main() {
     check((3, 5));
 //~^ ERROR mismatched types
+//~| HELP try with `&(3, 5)`
 }
diff --git a/src/test/compile-fail/issue-28514.rs b/src/test/compile-fail/issue-28514.rs
deleted file mode 100644 (file)
index 3488310..0000000
+++ /dev/null
@@ -1,47 +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.
-
-#![deny(private_in_public)]
-
-pub use inner::C;
-
-mod inner {
-    trait A {
-        fn a(&self) { }
-    }
-
-    pub trait B {
-        fn b(&self) { }
-    }
-
-    pub trait C: A + B { //~ ERROR private trait `inner::A` in public interface
-                         //~^ WARN will become a hard error
-        fn c(&self) { }
-    }
-
-    impl A for i32 {}
-    impl B for i32 {}
-    impl C for i32 {}
-
-}
-
-fn main() {
-    // A is private
-    // B is pub, not reexported
-    // C : A + B is pub, reexported
-
-    // 0.a(); // can't call
-    // 0.b(); // can't call
-    0.c(); // ok
-
-    C::a(&0); // can call
-    C::b(&0); // can call
-    C::c(&0); // ok
-}
index 06e8406cbc0bd15c3b7d531cc82058a71ec82eef..b7f767f109c0c7437ce421135f1c358bb7c16cfa 100644 (file)
@@ -28,10 +28,6 @@ pub struct Vector<T, D: Dim> {
 fn main() {
     let array: [usize; Dim3::dim()]
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error
-    //~| non-constant path in constant expression
         = [0; Dim3::dim()];
         //~^ ERROR calls in constants are limited to constant functions
-        //~| ERROR constant evaluation error
-        //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/issue-41394.rs b/src/test/compile-fail/issue-41394.rs
new file mode 100644 (file)
index 0000000..1fb3b7c
--- /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.
+
+enum Foo {
+    A = "" + 1
+    //~^ ERROR binary operation `+` cannot be applied to type `&'static str`
+}
+
+enum Bar {
+    A = Foo::A as isize
+}
+
+fn main() {}
index ea8796d38f93c36c542d89b23114924c6bc31b0c..a8d97d4674cbb4450f89bbc0c73332fd44e1c4e6 100644 (file)
@@ -16,7 +16,7 @@
 enum Bar { X }
 
 mod foo {
-    trait Bar {
+    pub trait Bar {
         fn method(&self) {}
 
         fn method2(&self) {}
diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
deleted file mode 100644 (file)
index cadfec5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 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.
-
-// Note: This test is checking that we forbid a coding pattern that
-// Issue #5873 explicitly wants to allow.
-
-enum State { ST_NULL, ST_WHITESPACE }
-
-fn main() {
-    [State::ST_NULL; (State::ST_WHITESPACE as usize)];
-    //~^ ERROR constant evaluation error
-    //~| unimplemented constant expression: enum variants
-}
diff --git a/src/test/compile-fail/object-safety-associated-consts.rs b/src/test/compile-fail/object-safety-associated-consts.rs
new file mode 100644 (file)
index 0000000..c442cd4
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+// Check that we correctly prevent users from making trait objects
+// from traits with associated consts.
+
+#![feature(associated_consts)]
+
+trait Bar {
+    const X: usize;
+}
+
+fn make_bar<T:Bar>(t: &T) -> &Bar {
+    //~^ ERROR E0038
+    //~| NOTE the trait cannot contain associated consts like `X`
+    //~| NOTE the trait `Bar` cannot be made into an object
+    t
+}
+
+fn main() {
+}
index bddcd391b205d5e80263f3c65a548abf12c57608..807be619f6c5f6ee71bfac6ffe4076ea7198d3b3 100644 (file)
@@ -18,7 +18,7 @@ pub union U {
     }
 }
 
-fn main() {
+fn main() { unsafe {
     let u = m::U { a: 0 }; // OK
     let u = m::U { b: 0 }; // OK
     let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private
@@ -26,4 +26,4 @@ fn main() {
     let m::U { a } = u; // OK
     let m::U { b } = u; // OK
     let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private
-}
+}}
diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs
new file mode 100644 (file)
index 0000000..eb0b27f
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+#![allow(dead_code)]
+#![feature(attr_literals)]
+#![feature(repr_align)]
+
+#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
+struct A(i32);
+
+#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+struct B(i32);
+
+#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768
+struct C(i32);
+
+fn main() {}
diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs
new file mode 100644 (file)
index 0000000..c584dcf
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+#![allow(dead_code)]
+
+#[repr(align(16))]
+struct A(i32);
+
+struct B(A);
+
+#[repr(packed)]
+struct C(A); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
+
+#[repr(packed)]
+struct D(B); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
+
+fn main() {}
diff --git a/src/test/compile-fail/trait-item-privacy.rs b/src/test/compile-fail/trait-item-privacy.rs
new file mode 100644 (file)
index 0000000..721d758
--- /dev/null
@@ -0,0 +1,135 @@
+// 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(associated_consts)]
+#![feature(associated_type_defaults)]
+
+struct S;
+
+mod method {
+    trait A {
+        fn a(&self) { }
+    }
+
+    pub trait B {
+        fn b(&self) { }
+    }
+
+    pub trait C: A + B {
+        fn c(&self) { }
+    }
+
+    impl A for ::S {}
+    impl B for ::S {}
+    impl C for ::S {}
+}
+
+mod assoc_const {
+    trait A {
+        const A: u8 = 0;
+    }
+
+    pub trait B {
+        const B: u8 = 0;
+    }
+
+    pub trait C: A + B {
+        const C: u8 = 0;
+    }
+
+    impl A for ::S {}
+    impl B for ::S {}
+    impl C for ::S {}
+}
+
+mod assoc_ty {
+    trait A {
+        type A = u8;
+    }
+
+    pub trait B {
+        type B = u8;
+    }
+
+    pub trait C: A + B {
+        type C = u8;
+    }
+
+    impl A for ::S {}
+    impl B for ::S {}
+    impl C for ::S {}
+}
+
+fn check_method() {
+    // A is private
+    // B is pub, not in scope
+    // C : A + B is pub, in scope
+    use method::C;
+
+    // Methods, method call
+    // a, b, c are resolved as trait items, their traits need to be in scope
+    S.a(); //~ ERROR no method named `a` found for type `S` in the current scope
+    S.b(); //~ ERROR no method named `b` found for type `S` in the current scope
+    S.c(); // OK
+    // a, b, c are resolved as inherent items, their traits don't need to be in scope
+    let c = &S as &C;
+    c.a(); //~ ERROR method `a` is private
+    c.b(); // OK
+    c.c(); // OK
+
+    // Methods, UFCS
+    // a, b, c are resolved as trait items, their traits need to be in scope
+    S::a(&S); //~ ERROR no associated item named `a` found for type `S` in the current scope
+    S::b(&S); //~ ERROR no associated item named `b` found for type `S` in the current scope
+    S::c(&S); // OK
+    // a, b, c are resolved as inherent items, their traits don't need to be in scope
+    C::a(&S); //~ ERROR method `a` is private
+    C::b(&S); // OK
+    C::c(&S); // OK
+}
+
+fn check_assoc_const() {
+    // A is private
+    // B is pub, not in scope
+    // C : A + B is pub, in scope
+    use assoc_const::C;
+
+    // Associated constants
+    // A, B, C are resolved as trait items, their traits need to be in scope
+    S::A; //~ ERROR no associated item named `A` found for type `S` in the current scope
+    S::B; //~ ERROR no associated item named `B` found for type `S` in the current scope
+    S::C; // OK
+    // A, B, C are resolved as inherent items, their traits don't need to be in scope
+    C::A; //~ ERROR associated constant `A` is private
+          //~^ ERROR the trait `assoc_const::C` cannot be made into an object
+          //~| ERROR the trait bound `assoc_const::C: assoc_const::A` is not satisfied
+    C::B; // ERROR the trait `assoc_const::C` cannot be made into an object
+          //~^ ERROR the trait bound `assoc_const::C: assoc_const::B` is not satisfied
+    C::C; // OK
+}
+
+fn check_assoc_ty<T: assoc_ty::C>() {
+    // A is private
+    // B is pub, not in scope
+    // C : A + B is pub, in scope
+    use assoc_ty::C;
+
+    // Associated types
+    // A, B, C are resolved as trait items, their traits need to be in scope, not implemented yet
+    let _: S::A; //~ ERROR ambiguous associated type
+    let _: S::B; //~ ERROR ambiguous associated type
+    let _: S::C; //~ ERROR ambiguous associated type
+    // A, B, C are resolved as inherent items, their traits don't need to be in scope
+    let _: T::A; //~ ERROR associated type `A` is private
+    let _: T::B; // OK
+    let _: T::C; // OK
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/trait-not-accessible.rs b/src/test/compile-fail/trait-not-accessible.rs
deleted file mode 100644 (file)
index 5feef0a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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.
-
-mod m {
-    trait Priv {
-        fn f(&self) {}
-    }
-    impl Priv for super::S {}
-    pub trait Pub: Priv {}
-}
-
-struct S;
-impl m::Pub for S {}
-
-fn g<T: m::Pub>(arg: T) {
-    arg.f(); //~ ERROR: source trait `m::Priv` is private
-}
-
-fn main() {
-    g(S);
-}
diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs
new file mode 100644 (file)
index 0000000..9dde526
--- /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.
+
+// compile-flags: -Z parse-only
+
+fn f<T: ?>() {} //~ ERROR expected identifier, found `>`
diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs
new file mode 100644 (file)
index 0000000..a44c0c3
--- /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.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+fn main() {
+    let _: Box<((Copy)) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))`
+    let _: Box<(Copy + Copy) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)`
+    let _: Box<(Copy +) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)`
+}
diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs
new file mode 100644 (file)
index 0000000..6be62d9
--- /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.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+fn f<T: Copy + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported
+
+fn main() {
+    let _: Box<Copy + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
+    let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a`
+}
diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs
new file mode 100644 (file)
index 0000000..dc44f4f
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+// compile-flags: -Z parse-only
+
+fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
+
+fn main() {
+    let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
+    let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
+    let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
+}
+
+FAIL //~ ERROR
index 49fec6f3619e4fa9c7ed48562281a8cfaf8d50e9..8ab8f4715755ddbef149777ab726c29d023afe0f 100644 (file)
@@ -12,7 +12,7 @@
 #![crate_type = "lib"]
 // we can compile to a variety of platforms, because we don't need
 // cross-compiled standard libraries.
-#![feature(no_core)]
+#![feature(no_core, optin_builtin_traits)]
 #![no_core]
 
 #![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)]
@@ -78,3 +78,7 @@ pub trait Copy { }
 pub mod marker {
     pub use Copy;
 }
+
+#[lang = "freeze"]
+trait Freeze {}
+impl Freeze for .. {}
index 15b56977232169cf5b8721ba0994cd9947712839..af24c3b460b2e844d43123eb9aaf9f6725967996 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(lang_items, no_core)]
+#![feature(lang_items, no_core, optin_builtin_traits)]
 #![no_core]
 
 #[lang="copy"]
@@ -17,6 +17,10 @@ trait Copy { }
 #[lang="sized"]
 trait Sized { }
 
+#[lang = "freeze"]
+trait Freeze {}
+impl Freeze for .. {}
+
 #[lang="start"]
 fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 }
 
diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs
new file mode 100644 (file)
index 0000000..0b9a359
--- /dev/null
@@ -0,0 +1,196 @@
+// 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.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+
+use std::mem;
+
+// Raising alignment
+#[repr(align(16))]
+struct Align16(i32);
+
+// Lowering has no effect
+#[repr(align(1))]
+struct Align1(i32);
+
+// Multiple attributes take the max
+#[repr(align(4))]
+#[repr(align(16))]
+#[repr(align(8))]
+struct AlignMany(i32);
+
+// Raising alignment may not alter size.
+#[repr(align(8))]
+#[allow(dead_code)]
+struct Align8Many {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: u8,
+}
+
+enum Enum {
+    #[allow(dead_code)]
+    A(i32),
+    B(Align16)
+}
+
+// Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test
+#[repr(C)]
+struct Nested {
+    a: i32,
+    b: i32,
+    c: Align16,
+    d: i8,
+}
+
+#[repr(packed)]
+struct Packed(i32);
+
+#[repr(align(16))]
+struct AlignContainsPacked {
+    a: Packed,
+    b: Packed,
+}
+
+impl Align16 {
+    // return aligned type
+    pub fn new(i: i32) -> Align16 {
+        Align16(i)
+    }
+    // pass aligned type
+    pub fn consume(a: Align16) -> i32 {
+        a.0
+    }
+}
+
+const CONST_ALIGN16: Align16 = Align16(7);
+static STATIC_ALIGN16: Align16 = Align16(8);
+
+// Check the actual address is aligned
+fn is_aligned_to<T>(p: &T, align: usize) -> bool {
+    let addr = p as *const T as usize;
+    (addr & (align - 1)) == 0
+}
+
+pub fn main() {
+    // check alignment and size by type and value
+    assert_eq!(mem::align_of::<Align16>(), 16);
+    assert_eq!(mem::size_of::<Align16>(), 16);
+
+    let a = Align16(7);
+    assert_eq!(a.0, 7);
+    assert_eq!(mem::align_of_val(&a), 16);
+    assert_eq!(mem::size_of_val(&a), 16);
+
+    assert!(is_aligned_to(&a, 16));
+
+    // lowering should have no effect
+    assert_eq!(mem::align_of::<Align1>(), 4);
+    assert_eq!(mem::size_of::<Align1>(), 4);
+    let a = Align1(7);
+    assert_eq!(a.0, 7);
+    assert_eq!(mem::align_of_val(&a), 4);
+    assert_eq!(mem::size_of_val(&a), 4);
+    assert!(is_aligned_to(&a, 4));
+
+    // when multiple attributes are specified the max should be used
+    assert_eq!(mem::align_of::<AlignMany>(), 16);
+    assert_eq!(mem::size_of::<AlignMany>(), 16);
+    let a = AlignMany(7);
+    assert_eq!(a.0, 7);
+    assert_eq!(mem::align_of_val(&a), 16);
+    assert_eq!(mem::size_of_val(&a), 16);
+    assert!(is_aligned_to(&a, 16));
+
+    // raising alignment should not reduce size
+    assert_eq!(mem::align_of::<Align8Many>(), 8);
+    assert_eq!(mem::size_of::<Align8Many>(), 16);
+    let a = Align8Many { a: 1, b: 2, c: 3, d: 4 };
+    assert_eq!(a.a, 1);
+    assert_eq!(mem::align_of_val(&a), 8);
+    assert_eq!(mem::size_of_val(&a), 16);
+    assert!(is_aligned_to(&a, 8));
+
+    // return type
+    let a = Align16::new(1);
+    assert_eq!(mem::align_of_val(&a), 16);
+    assert_eq!(mem::size_of_val(&a), 16);
+    assert_eq!(a.0, 1);
+    assert!(is_aligned_to(&a, 16));
+    assert_eq!(Align16::consume(a), 1);
+
+    // check const alignment, size and value
+    assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16);
+    assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16);
+    assert_eq!(CONST_ALIGN16.0, 7);
+    assert!(is_aligned_to(&CONST_ALIGN16, 16));
+
+    // check global static alignment, size and value
+    assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16);
+    assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16);
+    assert_eq!(STATIC_ALIGN16.0, 8);
+    assert!(is_aligned_to(&STATIC_ALIGN16, 16));
+
+    // Note that the size of Nested may change if struct field re-ordering is enabled
+    assert_eq!(mem::align_of::<Nested>(), 16);
+    assert_eq!(mem::size_of::<Nested>(), 48);
+    let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4};
+    assert_eq!(mem::align_of_val(&a), 16);
+    assert_eq!(mem::align_of_val(&a.b), 4);
+    assert_eq!(mem::align_of_val(&a.c), 16);
+    assert_eq!(mem::size_of_val(&a), 48);
+    assert!(is_aligned_to(&a, 16));
+    // check the correct fields are indexed
+    assert_eq!(a.a, 1);
+    assert_eq!(a.b, 2);
+    assert_eq!(a.c.0, 3);
+    assert_eq!(a.d, 4);
+
+    // enum should be aligned to max alignment
+    assert_eq!(mem::align_of::<Enum>(), 16);
+    assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16);
+    let e = Enum::B(Align16(15));
+    match e {
+        Enum::B(ref a) => {
+            assert_eq!(a.0, 15);
+            assert_eq!(mem::align_of_val(a), 16);
+            assert_eq!(mem::size_of_val(a), 16);
+        },
+        _ => ()
+    }
+    assert!(is_aligned_to(&e, 16));
+
+    // arrays of aligned elements should also be aligned
+    assert_eq!(mem::align_of::<[Align16;2]>(), 16);
+    assert_eq!(mem::size_of::<[Align16;2]>(), 32);
+
+    let a = [Align16(0), Align16(1)];
+    assert_eq!(mem::align_of_val(&a[0]), 16);
+    assert_eq!(mem::align_of_val(&a[1]), 16);
+    assert!(is_aligned_to(&a, 16));
+
+    // check heap value is aligned
+    assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16);
+
+    // check heap array is aligned
+    let a = vec!(Align16(0), Align16(1));
+    assert_eq!(mem::align_of_val(&a[0]), 16);
+    assert_eq!(mem::align_of_val(&a[1]), 16);
+
+    assert_eq!(mem::align_of::<AlignContainsPacked>(), 16);
+    assert_eq!(mem::size_of::<AlignContainsPacked>(), 16);
+    let a = AlignContainsPacked { a: Packed(1), b: Packed(2) };
+    assert_eq!(mem::align_of_val(&a), 16);
+    assert_eq!(mem::align_of_val(&a.a), 1);
+    assert_eq!(mem::align_of_val(&a.b), 1);
+    assert_eq!(mem::size_of_val(&a), 16);
+    assert!(is_aligned_to(&a, 16));
+}
diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs
new file mode 100644 (file)
index 0000000..f06b812
--- /dev/null
@@ -0,0 +1,26 @@
+// 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.
+
+#![crate_type = "lib"]
+
+#[repr(u32)]
+pub enum Foo {
+    Foo = Private::Variant as u32
+}
+
+#[repr(u8)]
+enum Private {
+    Variant = 42
+}
+
+#[inline(always)]
+pub fn foo() -> Foo {
+    Foo::Foo
+}
diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs
new file mode 100644 (file)
index 0000000..104ab6e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(const_fn)]
+
+#[derive(PartialEq, Eq)]
+enum Cake {
+    BlackForest,
+    Marmor,
+}
+use Cake::*;
+
+const BOO: (Cake, Cake) = (Marmor, BlackForest);
+const FOO: Cake = BOO.1;
+
+const fn foo() -> Cake {
+    Marmor
+}
+
+const WORKS: Cake = Marmor;
+
+const GOO: Cake = foo();
+
+fn main() {
+    match BlackForest {
+        FOO => println!("hi"),
+        GOO => println!("meh"),
+        WORKS => println!("möp"),
+        _ => println!("bye"),
+    }
+}
diff --git a/src/test/run-pass/issue-23898.rs b/src/test/run-pass/issue-23898.rs
new file mode 100644 (file)
index 0000000..3f5546c
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+// Note: This test was used to demonstrate #5873 (now #23898).
+
+enum State { ST_NULL, ST_WHITESPACE }
+
+fn main() {
+    [State::ST_NULL; (State::ST_WHITESPACE as usize)];
+}
index 9a77be049feebbebf3c3d175933fabe5c8eccc2b..cf925662fc3f3ff0b9e94b73f57c40d9bba17b65 100644 (file)
@@ -10,6 +10,8 @@
 
 // write_volatile causes an LLVM assert with composite types
 
+// ignore-emscripten See #41299: probably a bad optimization
+
 #![feature(volatile)]
 use std::ptr::{read_volatile, write_volatile};
 
diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs
new file mode 100644 (file)
index 0000000..7989055
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+// aux-build:issue-41394.rs
+
+extern crate issue_41394 as lib;
+
+fn main() {
+    assert_eq!(lib::foo() as u32, 42);
+}
index 5148be5af8307b208c504157c5eab6756e1312ba..17ea5b9a79489855c314adc38a5f985f53c5f5d5 100644 (file)
@@ -9,11 +9,22 @@
 // except according to those terms.
 
 // ignore-emscripten no threads support
-#![feature(rustc_attrs, zero_one)]
+#![feature(rustc_attrs)]
 
-use std::num::Zero;
 use std::thread;
 
+trait Int {
+    fn zero() -> Self;
+    fn one() -> Self;
+}
+macro_rules! doit {
+    ($($t:ident)*) => ($(impl Int for $t {
+        fn zero() -> $t { 0 }
+        fn one() -> $t { 1 }
+    })*)
+}
+doit! { i8 i16 i32 i64 isize }
+
 macro_rules! check {
     ($($e:expr),*) => {
         $(assert!(thread::spawn({
@@ -24,21 +35,21 @@ macro_rules! check {
 
 fn main() {
     check![
-        isize::min_value() / -1,
-        i8::min_value() / -1,
-        i16::min_value() / -1,
-        i32::min_value() / -1,
-        i64::min_value() / -1,
+        isize::min_value() / -isize::one(),
+        i8::min_value() / -i8::one(),
+        i16::min_value() / -i16::one(),
+        i32::min_value() / -i32::one(),
+        i64::min_value() / -i64::one(),
         1isize / isize::zero(),
         1i8 / i8::zero(),
         1i16 / i16::zero(),
         1i32 / i32::zero(),
         1i64 / i64::zero(),
-        isize::min_value() % -1,
-        i8::min_value() % -1,
-        i16::min_value() % -1,
-        i32::min_value() % -1,
-        i64::min_value() % -1,
+        isize::min_value() % -isize::one(),
+        i8::min_value() % -i8::one(),
+        i16::min_value() % -i16::one(),
+        i32::min_value() % -i32::one(),
+        i64::min_value() % -i64::one(),
         1isize % isize::zero(),
         1i8 % i8::zero(),
         1i16 % i16::zero(),
index 1c273fcba02daf77b148b7c9f44dd9779b4d416e..ebbb00a4a9f2322f6c0664f73eeb26d9708bf0db 100644 (file)
@@ -27,7 +27,17 @@ fn main() {
             exit_success_if_unwind::bar(do_panic);
         }
     }
-    let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
+
+    let mut cmd = Command::new(env::args_os().next().unwrap());
+    cmd.arg("foo");
+
+
+    // ARMv6 hanges while printing the backtrace, see #41004
+    if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") {
+        cmd.env("RUST_BACKTRACE", "0");
+    }
+
+    let s = cmd.status();
     assert!(s.unwrap().code() != Some(0));
 }
 
index be38f6ea3643a8857c7c553af3e2df34aa8ac59d..3ba3bd61c2e874db646cd8094e0a5e2fa254c3f2 100644 (file)
@@ -35,6 +35,15 @@ fn main() {
             panic!("try to catch me");
         }
     }
-    let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
+
+    let mut cmd = Command::new(env::args_os().next().unwrap());
+    cmd.arg("foo");
+
+    // ARMv6 hanges while printing the backtrace, see #41004
+    if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") {
+        cmd.env("RUST_BACKTRACE", "0");
+    }
+
+    let s = cmd.status();
     assert!(s.unwrap().code() != Some(0));
 }
index d046705c94bbe3261483b73f1752a8ac52b61752..ea154590deef0af432ff2ce192a7cb76ee60be33 100644 (file)
 
 #![allow(warnings)]
 #![feature(collections)]
-#![feature(drain, enumset, collections_bound, btree_range, vecmap)]
+#![feature(drain, collections_bound, btree_range, vecmap)]
 
 extern crate collections;
 
 use collections::BinaryHeap;
 use collections::{BTreeMap, BTreeSet};
-use collections::EnumSet;
 use collections::LinkedList;
 use collections::String;
 use collections::Vec;
@@ -25,7 +24,6 @@
 use std::collections::HashSet;
 
 use collections::Bound::Included;
-use collections::enum_set::CLike;
 use std::mem;
 
 fn is_sync<T>(_: T) where T: Sync {}
@@ -76,21 +74,6 @@ fn main() {
 
     all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter);
 
-    #[derive(Copy, Clone)]
-    #[repr(usize)]
-    #[allow(dead_code)]
-    enum Foo { A, B, C }
-    impl CLike for Foo {
-        fn to_usize(&self) -> usize {
-            *self as usize
-        }
-
-        fn from_usize(v: usize) -> Foo {
-            unsafe { mem::transmute(v) }
-        }
-    }
-    all_sync_send!(EnumSet::<Foo>::new(), iter);
-
     all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter);
     is_sync_send!(VecDeque::<usize>::new(), drain(..));
 
index 4eb66268ab8eab8fc55b20e60c6b7ed09a2db099..7a0b4c6aaca4922b62eddf73c0ab65a0096b2fca 100644 (file)
@@ -8,12 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(core_float)]
-#![feature(float_extras)]
 #![feature(untagged_unions)]
 
 extern crate core;
-use core::num::Float;
+use core::f32;
 
 union U {
     a: (u8, u8),
@@ -33,8 +31,8 @@ fn main() {
         assert_eq!(u.a, (2, 2));
 
         let mut w = W { a: 0b0_11111111_00000000000000000000000 };
-        assert_eq!(w.b, f32::infinity());
-        w.b = f32::neg_infinity();
+        assert_eq!(w.b, f32::INFINITY);
+        w.b = f32::NEG_INFINITY;
         assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
     }
 }
index 9ffba2c7999f1770966643689706329ec802a9eb..aed6986c5fe5d380b71a1fefc1fff776e0186ebe 100644 (file)
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 
-#![feature(binary_heap_extras)]
-
 use std::collections::BinaryHeap;
 
 fn make_pq() -> BinaryHeap<isize> {
diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs
deleted file mode 100644 (file)
index f048b64..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#![crate_name = "foo"]
-
-// ignore-tidy-end-whitespace
-
-// @has foo/fn.f.html
-// @has - '<p>hard break:<br />'
-// @has - 'after hard break</p>'
-/// hard break:  
-/// after hard break
-pub fn f() {}
diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs
deleted file mode 100644 (file)
index 4654267..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#![crate_name = "foo"]
-
-// ignore-tidy-linelength
-
-// @has foo/fn.f.html
-// @has - '<p>markdown test</p>'
-// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>'
-// @has - '<hr />'
-// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>'
-// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>'
-// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>'
-// @has - '<div class="footnotes"><hr><ol><li id="ref1">'
-// @has - '<p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
-// @has - '<p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
-/// markdown test
-///
-/// this is a [link].
-///
-/// [link]: https://example.com "this is a title"
-///
-/// -----------
-///
-/// a footnote[^footnote].
-///
-/// another footnote[^footnotebis].
-///
-/// [^footnote]: Thing
-///
-///
-/// [^footnotebis]: Another Thing
-///
-///
-/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
-pub fn f() {}
index 12b0ecabcc72053403e002fe6a506efe2185cf5d..af974d501839b35cb76d8ac7c746c244e25d4b6a 100644 (file)
@@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait
 15 |       fn renew<'b: 'a>(self) -> &'b mut [T];
    |       -------------------------------------- definition of `renew` from trait
 ...
-19 |       fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
-   |  _____^ starting here...
+19 | /     fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
 20 | |         //~^ ERROR E0276
 21 | |         &mut self[..]
 22 | |     }
-   | |_____^ ...ending here: impl has extra requirement `'a: 'b`
+   | |_____^ impl has extra requirement `'a: 'b`
 
 error: aborting due to previous error
 
index 77b056f69789249f722f0ac6c7e6f36f60d0e692..622e144c53a040447103654b7fb552c79d68c5b0 100644 (file)
@@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait
 19 |       fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
    |       ------------------------------------------------------------------ definition of `zip` from trait
 ...
-23 |       fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
-   |  _____^ starting here...
+23 | /     fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
 24 | |     //~^ ERROR E0276
 25 | |         ZipIterator{a: self, b: other}
 26 | |     }
-   | |_____^ ...ending here: impl has extra requirement `U: Iterator<B>`
+   | |_____^ impl has extra requirement `U: Iterator<B>`
 
 error: aborting due to previous error
 
index 29ff0cee3af5c1d82dfb74756dc9ced2803faaa4..8e8773eba3e222feb5c31bbe4f2029a69ef5df5d 100644 (file)
@@ -2,17 +2,17 @@ error: missing `fn`, `type`, or `const` for impl-item declaration
   --> $DIR/issue-40006.rs:11:9
    |
 11 |   impl X {
-   |  _________^ starting here...
+   |  _________^
 12 | |     Y
-   | |____^ ...ending here: missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, or `const`
 
 error: missing `fn`, `type`, or `const` for trait-item declaration
   --> $DIR/issue-40006.rs:17:10
    |
 17 |   trait X {
-   |  __________^ starting here...
+   |  __________^
 18 | |     X() {}
-   | |____^ ...ending here: missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, or `const`
 
 error: expected `[`, found `#`
   --> $DIR/issue-40006.rs:19:17
@@ -24,17 +24,17 @@ error: missing `fn`, `type`, or `const` for trait-item declaration
   --> $DIR/issue-40006.rs:19:21
    |
 19 |       fn xxx() { ### }
-   |  _____________________^ starting here...
+   |  _____________________^
 20 | |     L = M;
-   | |____^ ...ending here: missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, or `const`
 
 error: missing `fn`, `type`, or `const` for trait-item declaration
   --> $DIR/issue-40006.rs:20:11
    |
 20 |       L = M;
-   |  ___________^ starting here...
+   |  ___________^
 21 | |     Z = { 2 + 3 };
-   | |____^ ...ending here: missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, or `const`
 
 error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
   --> $DIR/issue-40006.rs:21:18
index 92e2fe8e9367e855f39a4ce10dc12f7e96818753..2c788e952edbfd455b29645f875bdded8cf4eedd 100644 (file)
@@ -1,26 +1,24 @@
 error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
   --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1
    |
-32 |   impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
-   |  _^ starting here...
+32 | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
 33 | |     //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
 34 | |
 35 | |     // (unsafe to access self.1  due to #[may_dangle] on A)
 36 | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
 37 | | }
-   | |_^ ...ending here
+   | |_^
 
 error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
   --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1
    |
-38 |   impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
-   |  _^ starting here...
+38 | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
 39 | |     //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
 40 | |
 41 | |     // (unsafe to access self.1 due to #[may_dangle] on 'a)
 42 | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
 43 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: aborting due to 2 previous errors
 
index 5a63d235a7f0736f0b191a987a39ee7b6d168171..b51b683a1ac3a5de798a8e3feaea1d315159574d 100644 (file)
@@ -1,11 +1,10 @@
 error: reached the type-length limit while instantiating `<T as Foo><(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...`
   --> $DIR/issue-37311.rs:23:5
    |
-23 |       fn recurse(&self) {
-   |  _____^ starting here...
+23 | /     fn recurse(&self) {
 24 | |         (self, self).recurse();
 25 | |     }
-   | |_____^ ...ending here
+   | |_____^
    |
    = note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate
 
index 85e05422ab3b2f2e58aae9ec34194294dbc425f6..cf272b63128e8a104f366212646ecac2af4cb3f1 100644 (file)
@@ -8,18 +8,18 @@ note: ...the reference is valid for the lifetime 'a as defined on the body at 11
   --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
    |
 11 |   fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-   |  ____________________________________________^ starting here...
+   |  ____________________________________________^
 12 | |     if x > y { x } else { y }
 13 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43
   --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
    |
 11 |   fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-   |  ____________________________________________^ starting here...
+   |  ____________________________________________^
 12 | |     if x > y { x } else { y }
 13 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: aborting due to previous error
 
index 6956a043cc694a4a8ee04375b23c0e658948e10c..6e03e66dd258f18c017e63f504d9d13ca13d006e 100644 (file)
@@ -10,18 +10,18 @@ note: the anonymous lifetime #2 defined on the body at 15:51...
   --> $DIR/ex2a-push-one-existing-name.rs:15:52
    |
 15 |   fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-   |  ____________________________________________________^ starting here...
+   |  ____________________________________________________^
 16 | |     x.push(y);
 17 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51
   --> $DIR/ex2a-push-one-existing-name.rs:15:52
    |
 15 |   fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-   |  ____________________________________________________^ starting here...
+   |  ____________________________________________________^
 16 | |     x.push(y);
 17 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: aborting due to previous error
 
index 990ae65ba9854193bfcf0f0d3918b60bcae13000..028f54ce97871d98251e85a182af34ec3a441428 100644 (file)
@@ -10,18 +10,18 @@ note: the anonymous lifetime #3 defined on the body at 15:43...
   --> $DIR/ex2b-push-no-existing-names.rs:15:44
    |
 15 |   fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-   |  ____________________________________________^ starting here...
+   |  ____________________________________________^
 16 | |     x.push(y);
 17 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43
   --> $DIR/ex2b-push-no-existing-names.rs:15:44
    |
 15 |   fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-   |  ____________________________________________^ starting here...
+   |  ____________________________________________^
 16 | |     x.push(y);
 17 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: aborting due to previous error
 
index 82f6c71ec1c2eb36314a56c70547593c393920d6..4621214419e42c157666ddd4e72e9af0aa7f7aab 100644 (file)
@@ -8,11 +8,11 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
   --> $DIR/ex2c-push-inference-variable.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let z = Ref { data: y.data };
 17 | |     x.push(z);
 18 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that reference does not outlive borrowed content
   --> $DIR/ex2c-push-inference-variable.rs:16:25
    |
@@ -22,11 +22,11 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
   --> $DIR/ex2c-push-inference-variable.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let z = Ref { data: y.data };
 17 | |     x.push(z);
 18 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>)
   --> $DIR/ex2c-push-inference-variable.rs:17:12
    |
index daa6ea2d91aa3b567334a89cf84fad9a32e713ab..a69694fdc2e5bb7cdbde99f8b763724fd3fa4baf 100644 (file)
@@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
   --> $DIR/ex2d-push-inference-variable-2.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     a.push(b);
 19 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that reference does not outlive borrowed content
   --> $DIR/ex2d-push-inference-variable-2.rs:17:25
    |
@@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
   --> $DIR/ex2d-push-inference-variable-2.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     a.push(b);
 19 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that expression is assignable (expected &mut std::vec::Vec<Ref<'_, i32>>, found &mut std::vec::Vec<Ref<'b, i32>>)
   --> $DIR/ex2d-push-inference-variable-2.rs:16:33
    |
index b679532a4d91086ef85d0a22b5a81541e9780e01..eff15bb794b76a8f602b3afdca71fffea5713f43 100644 (file)
@@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
   --> $DIR/ex2e-push-inference-variable-3.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     Vec::push(a, b);
 19 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that reference does not outlive borrowed content
   --> $DIR/ex2e-push-inference-variable-3.rs:17:25
    |
@@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
   --> $DIR/ex2e-push-inference-variable-3.rs:15:67
    |
 15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^ starting here...
+   |  ___________________________________________________________________^
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     Vec::push(a, b);
 19 | | }
-   | |_^ ...ending here
+   | |_^
 note: ...so that expression is assignable (expected &mut std::vec::Vec<Ref<'_, i32>>, found &mut std::vec::Vec<Ref<'b, i32>>)
   --> $DIR/ex2e-push-inference-variable-3.rs:16:33
    |
index c67c6113d17c54c0aab0dda783643e25158b69bb..36bdec8d43afef1b9ca5fba171743cca1963002b 100644 (file)
@@ -37,15 +37,14 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:42:5
    |
-42 |       X {
-   |  _____^ starting here...
+42 | /     X {
 43 | |         x: X {
 44 | |             x: "".to_string(),
 45 | |             y: 2,
 46 | |         },
 47 | |         y: 3,
 48 | |     }
-   | |_____^ ...ending here: expected struct `std::string::String`, found integral variable
+   | |_____^ expected struct `std::string::String`, found integral variable
    |
    = note: expected type `X<X<_, std::string::String>, std::string::String>`
               found type `X<X<_, {integer}>, {integer}>`
@@ -53,15 +52,14 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:52:5
    |
-52 |       X {
-   |  _____^ starting here...
+52 | /     X {
 53 | |         x: X {
 54 | |             x: "".to_string(),
 55 | |             y: 2,
 56 | |         },
 57 | |         y: "".to_string(),
 58 | |     }
-   | |_____^ ...ending here: expected struct `std::string::String`, found integral variable
+   | |_____^ expected struct `std::string::String`, found integral variable
    |
    = note: expected type `X<X<_, std::string::String>, _>`
               found type `X<X<_, {integer}>, _>`
index 5dd124ebcdff6c3cc01e8b7a1965038162ee8fb8..c8941fbf950734c021621508ef1ef3129a95af14 100644 (file)
@@ -2,9 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/main.rs:12:18
    |
 12 |       let x: u32 = (
-   |  __________________^ starting here...
+   |  __________________^
 13 | |     );
-   | |_____^ ...ending here: expected u32, found ()
+   | |_____^ expected u32, found ()
    |
    = note: expected type `u32`
               found type `()`
index 3313543454469073e8d16e034372d50ffde3cbac..503ce5618d486db165587ec6ccd283399e0ac5f2 100644 (file)
@@ -3,10 +3,9 @@ error: main function not found
 error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method`
   --> $DIR/m2.rs:20:1
    |
-20 |   impl m1::X for X {
-   |  _^ starting here...
+20 | / impl m1::X for X {
 21 | | }
-   | |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation
+   | |_^ missing `CONSTANT`, `Type`, `method` in implementation
    |
    = note: `CONSTANT` from trait: `const CONSTANT: u32;`
    = note: `Type` from trait: `type Type;`
diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs
new file mode 100644 (file)
index 0000000..e9b4314
--- /dev/null
@@ -0,0 +1,43 @@
+// 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.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how padding is handled: alignment
+// requirements can lead to the introduction of padding, either before
+// fields or at the end of the structure as a whole.
+//
+// It avoids using u64/i64 because on some targets that is only 4-byte
+// aligned (while on most it is 8-byte aligned) and so the resulting
+// padding and overall computed sizes can be quite different.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+#![allow(dead_code)]
+
+#[repr(align(16))]
+#[derive(Default)]
+struct A(i32);
+
+enum E {
+    A(i32),
+    B(A)
+}
+
+#[derive(Default)]
+struct S {
+    a: i32,
+    b: i32,
+    c: A,
+    d: i8,
+}
+
+fn main() {
+    let _s: S = Default::default();
+}
diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout
new file mode 100644 (file)
index 0000000..7df12f0
--- /dev/null
@@ -0,0 +1,16 @@
+print-type-size type: `E`: 32 bytes, alignment: 16 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `A`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `B`: 28 bytes
+print-type-size         padding: 12 bytes
+print-type-size         field `.0`: 16 bytes, alignment: 16 bytes
+print-type-size type: `S`: 32 bytes, alignment: 16 bytes
+print-type-size     field `.c`: 16 bytes
+print-type-size     field `.a`: 4 bytes
+print-type-size     field `.b`: 4 bytes
+print-type-size     field `.d`: 1 bytes
+print-type-size     end padding: 7 bytes
+print-type-size type: `A`: 16 bytes, alignment: 16 bytes
+print-type-size     field `.0`: 4 bytes
+print-type-size     end padding: 12 bytes
index 3177e858ff4fd3b89ada820f849ce3a9889ffc66..bc3122bf71c0e21056a40d31e75e4a41f6e032ed 100644 (file)
@@ -32,7 +32,6 @@ fn main() {
     //~| NOTE types differ in mutability
     //~| NOTE expected type `&mut std::string::String`
     //~| NOTE found type `&std::string::String`
-    //~| HELP try with `&mut y`
     test2(&y);
     //~^ ERROR E0308
     //~| NOTE types differ in mutability
index 6a70b8ff851d7aecf1d7eb82380e4113d9e905f4..220b2f471da9ad7aef33e4d22a67ab811adbb778 100644 (file)
@@ -18,11 +18,7 @@ error[E0308]: mismatched types
    |
    = note: expected type `&str`
               found type `std::string::String`
-   = help: here are some functions which might fulfill your needs:
-           - .as_str()
-           - .trim()
-           - .trim_left()
-           - .trim_right()
+   = help: try with `&String::new()`
 
 error[E0308]: mismatched types
   --> $DIR/coerce-suggestions.rs:30:10
@@ -34,18 +30,18 @@ error[E0308]: mismatched types
               found type `&std::string::String`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-suggestions.rs:36:11
+  --> $DIR/coerce-suggestions.rs:35:11
    |
-36 |     test2(&y);
+35 |     test2(&y);
    |           ^^ types differ in mutability
    |
    = note: expected type `&mut i32`
               found type `&std::string::String`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-suggestions.rs:42:9
+  --> $DIR/coerce-suggestions.rs:41:9
    |
-42 |     f = box f;
+41 |     f = box f;
    |         ^^^^^ cyclic type of infinite size
    |
    = note: expected type `_`
index 367af12bb6b1c2f122e667b001a41cacac78d00f..ae290b3b11aa79c5df19475fbd03aaab7ed839b1 100644 (file)
@@ -19,15 +19,14 @@ error[E0046]: not all trait items implemented, missing: `bar`
 16 |       fn bar(&self);
    |       -------------- `bar` from trait
 ...
-22 |   impl Foo for FooConstForMethod {
-   |  _^ starting here...
+22 | / impl Foo for FooConstForMethod {
 23 | |     //~^ ERROR E0046
 24 | |     //~| NOTE missing `bar` in implementation
 25 | |     const bar: u64 = 1;
 ...  |
 28 | |     const MY_CONST: u32 = 1;
 29 | | }
-   | |_^ ...ending here: missing `bar` in implementation
+   | |_^ missing `bar` in implementation
 
 error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:37:5
@@ -44,15 +43,14 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST`
 17 |       const MY_CONST: u32;
    |       -------------------- `MY_CONST` from trait
 ...
-33 |   impl Foo for FooMethodForConst {
-   |  _^ starting here...
+33 | / impl Foo for FooMethodForConst {
 34 | |     //~^ ERROR E0046
 35 | |     //~| NOTE missing `MY_CONST` in implementation
 36 | |     fn bar(&self) {}
 ...  |
 39 | |     //~| NOTE does not match trait
 40 | | }
-   | |_^ ...ending here: missing `MY_CONST` in implementation
+   | |_^ missing `MY_CONST` in implementation
 
 error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:47:5
@@ -69,23 +67,21 @@ error[E0046]: not all trait items implemented, missing: `bar`
 16 |       fn bar(&self);
    |       -------------- `bar` from trait
 ...
-44 |   impl Foo for FooTypeForMethod {
-   |  _^ starting here...
+44 | / impl Foo for FooTypeForMethod {
 45 | |     //~^ ERROR E0046
 46 | |     //~| NOTE missing `bar` in implementation
 47 | |     type bar = u64;
 ...  |
 50 | |     const MY_CONST: u32 = 1;
 51 | | }
-   | |_^ ...ending here: missing `bar` in implementation
+   | |_^ missing `bar` in implementation
 
 error[E0046]: not all trait items implemented, missing: `fmt`
   --> $DIR/impl-wrong-item-for-trait.rs:53:1
    |
-53 |   impl Debug for FooTypeForMethod {
-   |  _^ starting here...
+53 | / impl Debug for FooTypeForMethod {
 54 | | }
-   | |_^ ...ending here: missing `fmt` in implementation
+   | |_^ missing `fmt` in implementation
    |
    = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
 
index 701576ff6f475bf59e4eeb74eed2a637b7043968..d9f4bacce35ae0650c9d88c39f58329dab187dcc 100644 (file)
@@ -1,15 +1,14 @@
 error[E0046]: not all trait items implemented, missing: `Item`
   --> $DIR/issue-23729.rs:20:9
    |
-20 |           impl Iterator for Recurrence {
-   |  _________^ starting here...
+20 | /         impl Iterator for Recurrence {
 21 | |             //~^ ERROR E0046
 22 | |             //~| NOTE missing `Item` in implementation
 23 | |             //~| NOTE `Item` from trait: `type Item;`
 ...  |
 36 | |             }
 37 | |         }
-   | |_________^ ...ending here: missing `Item` in implementation
+   | |_________^ missing `Item` in implementation
    |
    = note: `Item` from trait: `type Item;`
 
index 457fed34ff1ad9807d41d62889090436273f9472..3127af157a62bbb8184673b6398e6f4993db4230 100644 (file)
@@ -1,15 +1,14 @@
 error[E0046]: not all trait items implemented, missing: `Output`
   --> $DIR/issue-23827.rs:36:1
    |
-36 |   impl<C: Component> FnOnce<(C,)> for Prototype {
-   |  _^ starting here...
+36 | / impl<C: Component> FnOnce<(C,)> for Prototype {
 37 | |     //~^ ERROR E0046
 38 | |     //~| NOTE missing `Output` in implementation
 39 | |     //~| NOTE `Output` from trait: `type Output;`
 ...  |
 42 | |     }
 43 | | }
-   | |_^ ...ending here: missing `Output` in implementation
+   | |_^ missing `Output` in implementation
    |
    = note: `Output` from trait: `type Output;`
 
index 963f4bd9bbcd8ac432569b16b33e304de5e535ea..71ab82d98b809abee614d08c740e37a5266d8ee6 100644 (file)
@@ -1,14 +1,13 @@
 error[E0046]: not all trait items implemented, missing: `Target`
   --> $DIR/issue-24356.rs:30:9
    |
-30 |           impl Deref for Thing {
-   |  _________^ starting here...
+30 | /         impl Deref for Thing {
 31 | |             //~^ ERROR E0046
 32 | |             //~| NOTE missing `Target` in implementation
 33 | |             //~| NOTE `Target` from trait: `type Target;`
 34 | |             fn deref(&self) -> i8 { self.0 }
 35 | |         }
-   | |_________^ ...ending here: missing `Target` in implementation
+   | |_________^ missing `Target` in implementation
    |
    = note: `Target` from trait: `type Target;`
 
diff --git a/src/test/ui/span/issue-33884.rs b/src/test/ui/span/issue-33884.rs
new file mode 100644 (file)
index 0000000..93aa502
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+use std::net::TcpListener;
+use std::net::TcpStream;
+use std::io::{self, Read, Write};
+
+fn handle_client(stream: TcpStream) -> io::Result<()> {
+    stream.write_fmt(format!("message received"))
+}
+
+fn main() {
+    if let Ok(listener) = TcpListener::bind("127.0.0.1:8080") {
+        for incoming in listener.incoming() {
+            if let Ok(stream) = incoming {
+                handle_client(stream);
+            }
+        }
+    }
+}
diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr
new file mode 100644 (file)
index 0000000..2a87418
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-33884.rs:16:22
+   |
+16 |     stream.write_fmt(format!("message received"))
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::fmt::Arguments`, found struct `std::string::String`
+   |
+   = note: expected type `std::fmt::Arguments<'_>`
+              found type `std::string::String`
+   = note: this error originates in a macro outside of the current crate
+
+error: aborting due to previous error
+
index 765aceffe655b54c9fb3de9c059026e867e5f06d..8b813220d789de781b21f5dc635f3aa882cb2003 100644 (file)
@@ -38,11 +38,10 @@ error: no method named `fff` found for type `Myisize` in the current scope
 note: candidate #1 is defined in an impl for the type `Myisize`
   --> $DIR/issue-7575.rs:51:5
    |
-51 |       fn fff(i: isize) -> isize { //~ NOTE candidate
-   |  _____^ starting here...
+51 | /     fn fff(i: isize) -> isize { //~ NOTE candidate
 52 | |         i
 53 | |     }
-   | |_____^ ...ending here
+   | |_____^
 
 error: no method named `is_str` found for type `T` in the current scope
   --> $DIR/issue-7575.rs:85:7
@@ -54,11 +53,10 @@ error: no method named `is_str` found for type `T` in the current scope
 note: candidate #1 is defined in the trait `ManyImplTrait`
   --> $DIR/issue-7575.rs:57:5
    |
-57 |       fn is_str() -> bool { //~ NOTE candidate
-   |  _____^ starting here...
+57 | /     fn is_str() -> bool { //~ NOTE candidate
 58 | |         false
 59 | |     }
-   | |_____^ ...ending here
+   | |_____^
    = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead
    = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `is_str`, perhaps you need to implement it:
    = help: candidate #1: `ManyImplTrait`
index 0df3fa43022a485c3c993512a3602d18a6263d00..f4998e08907a387f55b897ab80f5cc47e203d540 100644 (file)
@@ -49,68 +49,62 @@ note: because it's nested under this `unsafe` fn
 error: unnecessary `unsafe` block
   --> $DIR/lint-unused-unsafe.rs:33:9
    |
-33 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
-   |  _________^ starting here...
+33 | /         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 34 | |             unsf()
 35 | |         }
-   | |_________^ ...ending here: unnecessary `unsafe` block
+   | |_________^ unnecessary `unsafe` block
    |
 note: because it's nested under this `unsafe` block
   --> $DIR/lint-unused-unsafe.rs:32:5
    |
-32 |       unsafe {                             // don't put the warning here
-   |  _____^ starting here...
+32 | /     unsafe {                             // don't put the warning here
 33 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 34 | |             unsf()
 35 | |         }
 36 | |     }
-   | |_____^ ...ending here
+   | |_____^
 
 error: unnecessary `unsafe` block
   --> $DIR/lint-unused-unsafe.rs:39:5
    |
-39 |       unsafe {                             //~ ERROR: unnecessary `unsafe` block
-   |  _____^ starting here...
+39 | /     unsafe {                             //~ ERROR: unnecessary `unsafe` block
 40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 41 | |             unsf()
 42 | |         }
 43 | |     }
-   | |_____^ ...ending here: unnecessary `unsafe` block
+   | |_____^ unnecessary `unsafe` block
    |
 note: because it's nested under this `unsafe` fn
   --> $DIR/lint-unused-unsafe.rs:38:1
    |
-38 |   unsafe fn bad7() {
-   |  _^ starting here...
+38 | / unsafe fn bad7() {
 39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
 40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 41 | |             unsf()
 42 | |         }
 43 | |     }
 44 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: unnecessary `unsafe` block
   --> $DIR/lint-unused-unsafe.rs:40:9
    |
-40 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
-   |  _________^ starting here...
+40 | /         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 41 | |             unsf()
 42 | |         }
-   | |_________^ ...ending here: unnecessary `unsafe` block
+   | |_________^ unnecessary `unsafe` block
    |
 note: because it's nested under this `unsafe` fn
   --> $DIR/lint-unused-unsafe.rs:38:1
    |
-38 |   unsafe fn bad7() {
-   |  _^ starting here...
+38 | / unsafe fn bad7() {
 39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
 40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
 41 | |             unsf()
 42 | |         }
 43 | |     }
 44 | | }
-   | |_^ ...ending here
+   | |_^
 
 error: aborting due to 8 previous errors
 
index 58cdc50230063cc99470275eadd2b8cda8ad8973..9c6816e736313c534e6bc6df1579a47e9bfcbcce 100644 (file)
@@ -1,14 +1,13 @@
 error[E0072]: recursive type `ListNode` has infinite size
   --> $DIR/multiline-span-E0072.rs:12:1
    |
-12 |   struct
-   |  _^ starting here...
+12 | / struct
 13 | | ListNode
 14 | | {
 15 | |     head: u8,
 16 | |     tail: Option<ListNode>,
 17 | | }
-   | |_^ ...ending here: recursive type has infinite size
+   | |_^ recursive type has infinite size
    |
    = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
 
index 161b6ca48b282444edf6150f4d847eb7df3903a6..843c1e811d578393ea375cc42338d38a773e7749 100644 (file)
@@ -2,12 +2,12 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
   --> $DIR/multiline-span-simple.rs:23:9
    |
 23 |       foo(1 as u32 +
-   |  _________^ starting here...
+   |  _________^
 24 | |
 25 | |         bar(x,
 26 | |
 27 | |             y),
-   | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32`
+   | |______________^ the trait `std::ops::Add<()>` is not implemented for `u32`
    |
    = note: no implementation for `u32 + ()`
 
index 5c388c9d602eab7e6f1c28927422a8dcff3b888f..7a76799889b97385d114fe863b94ed0573acc925 100644 (file)
@@ -1,15 +1,14 @@
 error[E0282]: type annotations needed
   --> $DIR/issue-40294.rs:15:1
    |
-15 |   fn foo<'a,'b,T>(x: &'a T, y: &'b T)
-   |  _^ starting here...
+15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T)
 16 | |     where &'a T : Foo,
 17 | |           &'b T : Foo
 18 | | {
 19 | |     x.foo();
 20 | |     y.foo();
 21 | | }
-   | |_^ ...ending here: cannot infer type for `&'a T`
+   | |_^ cannot infer type for `&'a T`
 
 error: aborting due to previous error
 
index 28c8d22707325f82eb80172e1dc297468511c96d..a8cb30da43513944b842a7946d06f1730d287374 100644 (file)
@@ -81,6 +81,7 @@
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "wasm32-unknown-emscripten",
+    "x86_64-linux-android",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
     "x86_64-pc-windows-gnu",
index c7113edbf9e68dc466679c0c5690ceb80c2b8b14..012ee835494e8e3120d0c973a243918d23ec8544 100644 (file)
@@ -22,12 +22,6 @@ struct Test {
 }
 
 const TEST_REPOS: &'static [Test] = &[
-    Test {
-        name: "cargo",
-        repo: "https://github.com/rust-lang/cargo",
-        sha: "0e1e34be7540bdaed4918457654fbf028cf69e56",
-        lock: None,
-    },
     Test {
         name: "iron",
         repo: "https://github.com/iron/iron",
@@ -61,20 +55,6 @@ struct Test {
 ];
 
 fn main() {
-    // One of the projects being tested here is Cargo, and when being tested
-    // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately
-    // `nmake` will read these two environment variables below and try to
-    // intepret them. We're likely being run, however, from MSYS `make` which
-    // uses the same variables.
-    //
-    // As a result, to prevent confusion and errors, we remove these variables
-    // from our environment to prevent passing MSYS make flags to nmake, causing
-    // it to blow up.
-    if cfg!(target_env = "msvc") {
-        env::remove_var("MAKE");
-        env::remove_var("MAKEFLAGS");
-    }
-
     let args = env::args().collect::<Vec<_>>();
     let ref cargo = args[1];
     let out_dir = Path::new(&args[2]);
index efadde992277fefe4b0c6544375487aa47ea6449..ca383b5add011533e4bba7cd61057ac6c68946f1 100644 (file)
@@ -24,7 +24,7 @@
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::{Markdown, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -100,7 +100,7 @@ fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
 
         // Description rendered as markdown.
         match info.description {
-            Some(ref desc) => write!(output, "{}", Markdown(desc))?,
+            Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?,
             None => write!(output, "<p>No description.</p>\n")?,
         }