]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #38858 - ollie27:rustbuild_docs_std, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 7 Jan 2017 04:02:43 +0000 (04:02 +0000)
committerbors <bors@rust-lang.org>
Sat, 7 Jan 2017 04:02:43 +0000 (04:02 +0000)
rustbuild: Stop building docs for std dependancies

Fixes: #38319
r? @alexcrichton

250 files changed:
.travis.yml
configure
src/bootstrap/Cargo.toml
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/step.rs
src/ci/docker/dist-arm-unknown-linux-gnueabi/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-x86_64-unknown-freebsd/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-x86_64-unknown-freebsd/build-toolchain.sh [new file with mode: 0644]
src/ci/docker/x86_64-freebsd/Dockerfile [deleted file]
src/ci/docker/x86_64-freebsd/build-toolchain.sh [deleted file]
src/doc/book/SUMMARY.md
src/doc/book/procedural-macros.md [new file with mode: 0644]
src/doc/book/strings.md
src/doc/nomicon/atomics.md
src/doc/nomicon/meet-safe-and-unsafe.md
src/doc/nomicon/races.md
src/doc/reference.md
src/etc/debugger_pretty_printers_common.py
src/etc/lldb_rust_formatters.py
src/libcollectionstest/str.rs
src/libcore/marker.rs
src/libcore/str/mod.rs
src/liblibc
src/libproc_macro/lib.rs
src/librustc/infer/error_reporting.rs
src/librustc/lint/builtin.rs
src/librustc/middle/dead.rs
src/librustc/middle/stability.rs
src/librustc/mir/mod.rs
src/librustc/session/config.rs
src/librustc/ty/context.rs
src/librustc/ty/inhabitedness/def_id_forest.rs [new file with mode: 0644]
src/librustc/ty/inhabitedness/mod.rs [new file with mode: 0644]
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc/ty/util.rs
src/librustc_back/target/redox_base.rs
src/librustc_const_eval/_match.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/diagnostics.rs
src/librustc_const_eval/eval.rs
src/librustc_const_eval/pattern.rs
src/librustc_data_structures/accumulate_vec.rs
src/librustc_data_structures/array_vec.rs
src/librustc_data_structures/lib.rs
src/librustc_driver/driver.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_metadata/lib.rs
src/librustc_mir/build/matches/simplify.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/abi.rs
src/librustc_trans/adt.rs
src/librustc_trans/asm.rs
src/librustc_trans/base.rs
src/librustc_trans/builder.rs
src/librustc_trans/callee.rs
src/librustc_trans/cleanup.rs
src/librustc_trans/common.rs
src/librustc_trans/debuginfo/create_scope_map.rs
src/librustc_trans/debuginfo/doc.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/source_loc.rs
src/librustc_trans/glue.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/meth.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_trans/mir/statement.rs
src/librustc_trans/tvec.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/coherence/builtin.rs [new file with mode: 0644]
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/libstd/net/tcp.rs
src/libstd/sys/redox/net/mod.rs
src/libstd/sys/redox/net/tcp.rs
src/libstd/sys/redox/net/udp.rs
src/libstd/sys/redox/syscall/data.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/pipe.rs
src/libstd/sys/windows/process.rs
src/libstd/sys/windows/thread_local.rs
src/libstd/thread/mod.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/lib.rs
src/libsyntax_ext/proc_macro_registrar.rs
src/rt/rust_test_helpers.c
src/test/codegen/stores.rs
src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/explore-issue-38412.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/attribute.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-b.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-bad.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-panic.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable-2.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_38586.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/define-two.rs
src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs
src/test/compile-fail-fulldeps/proc-macro/derive-still-gated.rs
src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs
src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs
src/test/compile-fail-fulldeps/proc-macro/export-macro.rs
src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs [deleted file]
src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs [deleted file]
src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs [deleted file]
src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs [deleted file]
src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs [deleted file]
src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs
src/test/compile-fail-fulldeps/proc-macro/import.rs
src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs
src/test/compile-fail-fulldeps/proc-macro/issue-38586.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/item-error.rs
src/test/compile-fail-fulldeps/proc-macro/load-panic.rs
src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs
src/test/compile-fail-fulldeps/proc-macro/pub-at-crate-root.rs
src/test/compile-fail-fulldeps/proc-macro/shadow-builtin.rs
src/test/compile-fail-fulldeps/proc-macro/shadow.rs
src/test/compile-fail-fulldeps/proc-macro/signature.rs
src/test/compile-fail/E0001.rs
src/test/compile-fail/E0204.rs [deleted file]
src/test/compile-fail/E0205.rs [deleted file]
src/test/compile-fail/const-eval-overflow0.rs [deleted file]
src/test/compile-fail/feature-gate-negate-unsigned.rs
src/test/compile-fail/feature-gate-negate-unsigned0.rs [deleted file]
src/test/compile-fail/issue-12116.rs
src/test/compile-fail/issue-12369.rs
src/test/compile-fail/issue-13727.rs
src/test/compile-fail/issue-14221.rs
src/test/compile-fail/issue-27942.rs [new file with mode: 0644]
src/test/compile-fail/issue-30240-b.rs [new file with mode: 0644]
src/test/compile-fail/issue-30240.rs
src/test/compile-fail/issue-30302.rs
src/test/compile-fail/issue-31221.rs
src/test/compile-fail/issue-3601.rs
src/test/compile-fail/issue-37884.rs [new file with mode: 0644]
src/test/compile-fail/issue-38412.rs [new file with mode: 0644]
src/test/compile-fail/lint-qualification.rs
src/test/compile-fail/match-argm-statics-2.rs [new file with mode: 0644]
src/test/compile-fail/match-arm-statics.rs
src/test/compile-fail/match-byte-array-patterns-2.rs [new file with mode: 0644]
src/test/compile-fail/match-byte-array-patterns.rs
src/test/compile-fail/match-range-fail-dominate.rs
src/test/compile-fail/match-ref-ice.rs
src/test/compile-fail/match-slice-patterns.rs
src/test/compile-fail/match-vec-fixed.rs
src/test/compile-fail/match-vec-unreachable.rs
src/test/compile-fail/struct-pattern-match-useless.rs
src/test/compile-fail/uninhabited-irrefutable.rs [new file with mode: 0644]
src/test/compile-fail/uninhabited-patterns.rs [new file with mode: 0644]
src/test/compile-fail/unreachable-arm.rs
src/test/debuginfo/issue-12886.rs [new file with mode: 0644]
src/test/debuginfo/issue-13213.rs [new file with mode: 0644]
src/test/debuginfo/issue-14411.rs [new file with mode: 0644]
src/test/debuginfo/issue-22656.rs [new file with mode: 0644]
src/test/debuginfo/issue-7712.rs [new file with mode: 0644]
src/test/debuginfo/issue12886.rs [deleted file]
src/test/debuginfo/issue13213.rs [deleted file]
src/test/debuginfo/issue14411.rs [deleted file]
src/test/debuginfo/issue22656.rs [deleted file]
src/test/debuginfo/issue7712.rs [deleted file]
src/test/debuginfo/union-smoke.rs
src/test/debuginfo/unsized.rs [new file with mode: 0644]
src/test/run-make/issue-37839/a.rs
src/test/run-make/issue-37893/a.rs
src/test/run-make/issue-38237/foo.rs
src/test/run-make/rustc-macro-dep-files/bar.rs
src/test/run-make/rustc-macro-dep-files/foo.rs
src/test/run-make/test-harness/Makefile
src/test/run-pass-fulldeps/proc-macro/add-impl.rs
src/test/run-pass-fulldeps/proc-macro/append-impl.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-ctod.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-nothing.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs
src/test/run-pass-fulldeps/proc-macro/crate-var.rs
src/test/run-pass-fulldeps/proc-macro/derive-b.rs
src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs
src/test/run-pass-fulldeps/proc-macro/derive-test.rs
src/test/run-pass-fulldeps/proc-macro/expand-with-a-macro.rs
src/test/run-pass-fulldeps/proc-macro/load-two.rs
src/test/run-pass-fulldeps/proc-macro/smoke.rs
src/test/run-pass-fulldeps/proc-macro/struct-field-macro.rs
src/test/run-pass-fulldeps/proc-macro/use-reexport.rs
src/test/run-pass/auxiliary/issue_38715.rs [new file with mode: 0644]
src/test/run-pass/empty-types-in-patterns.rs [new file with mode: 0644]
src/test/run-pass/i128-ffi.rs [new file with mode: 0644]
src/test/run-pass/i128.rs
src/test/run-pass/issue-18173.rs [new file with mode: 0644]
src/test/run-pass/issue-22008.rs [new file with mode: 0644]
src/test/run-pass/issue-22346.rs [new file with mode: 0644]
src/test/run-pass/issue-24353.rs [new file with mode: 0644]
src/test/run-pass/issue-26127.rs [new file with mode: 0644]
src/test/run-pass/issue-29927.rs [new file with mode: 0644]
src/test/run-pass/issue-32947.rs [new file with mode: 0644]
src/test/run-pass/issue-33187.rs [new file with mode: 0644]
src/test/run-pass/issue-34569.rs [new file with mode: 0644]
src/test/run-pass/issue-34796.rs [new file with mode: 0644]
src/test/run-pass/issue-36260.rs [new file with mode: 0644]
src/test/run-pass/issue-37991.rs [new file with mode: 0644]
src/test/run-pass/issue-38715.rs [new file with mode: 0644]
src/test/run-pass/issue-38727.rs [new file with mode: 0644]
src/test/run-pass/issue18173.rs [deleted file]
src/test/run-pass/issue22008.rs [deleted file]
src/test/run-pass/issue22346.rs [deleted file]
src/test/run-pass/issue24353.rs [deleted file]
src/test/run-pass/issue26127.rs [deleted file]
src/test/run-pass/issue29927.rs [deleted file]
src/test/run-pass/issue34569.rs [deleted file]
src/test/run-pass/issue34796.rs [deleted file]
src/test/run-pass/issue36260.rs [deleted file]
src/test/run-pass/stdio-is-blocking.rs [new file with mode: 0644]
src/test/run-pass/test-allow-dead-extern-static-no-warning.rs [new file with mode: 0644]
src/test/run-pass/u128.rs
src/test/rustdoc/rustc-macro-crate.rs
src/test/ui/check_match/issue-35609.stderr
src/test/ui/span/E0204.rs [new file with mode: 0644]
src/test/ui/span/E0204.stderr [new file with mode: 0644]

index 26cabf92bdac81d98ced0ba6cee456f199092458..15b610833b0efd53bfa46a377fc5dda6651bdde1 100644 (file)
@@ -15,9 +15,10 @@ matrix:
     # Linux builders, all docker images
     - env: IMAGE=arm-android
     - env: IMAGE=cross
+    - env: IMAGE=dist-arm-unknown-linux-gnueabi
+    - env: IMAGE=dist-x86_64-unknown-freebsd
     - env: IMAGE=i686-gnu
     - env: IMAGE=i686-gnu-nopt
-    - env: IMAGE=x86_64-freebsd
     - env: IMAGE=x86_64-gnu
     - env: IMAGE=x86_64-gnu-full-bootstrap
     - env: IMAGE=x86_64-gnu-aux
index beb0a9d43a0cf4cd87b2a48da157c64e5589cbfc..ee5922b1f142db0c948d313fdd57f8887f953502 100755 (executable)
--- a/configure
+++ b/configure
@@ -1568,7 +1568,7 @@ do
     then
         LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
         LLVM_INST_DIR=$LLVM_BUILD_DIR
-        # For some crazy reason the MSVC output dir is different than Unix
+        # For some weird reason the MSVC output dir is different than Unix
         if [ ${is_msvc} -ne 0 ]; then
             if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
             then
index 35f8fb43f7b562b6321bcd5e3fe1ef425b7aca89..1eda1608c4709c4de84b57b8473ca62cbbaad820 100644 (file)
@@ -6,18 +6,22 @@ version = "0.0.0"
 [lib]
 name = "bootstrap"
 path = "lib.rs"
+doctest = false
 
 [[bin]]
 name = "bootstrap"
 path = "bin/main.rs"
+test = false
 
 [[bin]]
 name = "rustc"
 path = "bin/rustc.rs"
+test = false
 
 [[bin]]
 name = "rustdoc"
 path = "bin/rustdoc.rs"
+test = false
 
 [dependencies]
 build_helper = { path = "../build_helper" }
index 6db1afa54a625493c868ca3c419744c5ccc1124c..f2fddf6e2ef3aee31350322dc826f8ee83f4847e 100644 (file)
@@ -568,3 +568,14 @@ pub fn distcheck(build: &Build) {
                      .arg("check")
                      .current_dir(&dir));
 }
+
+/// Test the build system itself
+pub fn bootstrap(build: &Build) {
+    let mut cmd = Command::new(&build.cargo);
+    cmd.arg("test")
+       .current_dir(build.src.join("src/bootstrap"))
+       .env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
+       .env("RUSTC", &build.rustc);
+    cmd.arg("--").args(&build.flags.cmd.test_args());
+    build.run(&mut cmd);
+}
index a7633998aad8bc484235233c2d11d94e24958751..31f8754d2091e69abd4c0b97a26995cdc6b52dba 100644 (file)
@@ -258,11 +258,6 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
 }
 
 pub fn create_sysroot(build: &Build, compiler: &Compiler) {
-    // nothing to do in stage0
-    if compiler.stage == 0 {
-        return
-    }
-
     let sysroot = build.sysroot(compiler);
     let _ = fs::remove_dir_all(&sysroot);
     t!(fs::create_dir_all(&sysroot));
@@ -396,7 +391,7 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
 /// all files in a directory and updating the stamp if any are newer.
 fn update_mtime(path: &Path) {
     let mut max = None;
-    if let Ok(entries) = path.parent().unwrap().read_dir() {
+    if let Ok(entries) = path.parent().unwrap().join("deps").read_dir() {
         for entry in entries.map(|e| t!(e)) {
             if t!(entry.file_type()).is_file() {
                 let meta = t!(entry.metadata());
index 428c3da77648ca762df9690121b36afaddd8cd8a..ad851e448ea7c9e3ceb68cd5be3309e5f84587b6 100644 (file)
@@ -320,10 +320,18 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
         return
     }
 
+    // Package save-analysis from stage1 if not doing a full bootstrap, as the
+    // stage2 artifacts is simply copied from stage1 in that case.
+    let compiler = if build.force_use_stage1(compiler, target) {
+        Compiler::new(1, compiler.host)
+    } else {
+        compiler.clone()
+    };
+
     let name = format!("rust-analysis-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-{}-image", name, target));
 
-    let src = build.stage_out(compiler, Mode::Libstd).join(target).join("release").join("deps");
+    let src = build.stage_out(&compiler, Mode::Libstd).join(target).join("release").join("deps");
 
     let image_src = src.join("save-analysis");
     let dst = image.join("lib/rustlib").join(target).join("analysis");
@@ -346,14 +354,9 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
 }
 
 /// Creates the `rust-src` installer component and the plain source tarball
-pub fn rust_src(build: &Build, host: &str) {
+pub fn rust_src(build: &Build) {
     println!("Dist src");
 
-    if host != build.config.build {
-        println!("\tskipping, not a build host");
-        return
-    }
-
     let plain_name = format!("rustc-{}-src", package_vers(build));
     let name = format!("rust-src-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-image", name));
index 5213b695216f268236ce934f01a5a0af99c916be..2b063741c07401c83038f5c7ac351b25c49a6639 100644 (file)
@@ -57,12 +57,12 @@ pub fn rustbook(build: &Build, target: &str, name: &str) {
 /// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
 ///
 /// In the end, this is just a glorified wrapper around rustdoc!
-pub fn standalone(build: &Build, stage: u32, target: &str) {
-    println!("Documenting stage{} standalone ({})", stage, target);
+pub fn standalone(build: &Build, target: &str) {
+    println!("Documenting standalone ({})", target);
     let out = build.doc_out(target);
     t!(fs::create_dir_all(&out));
 
-    let compiler = Compiler::new(stage, &build.config.build);
+    let compiler = Compiler::new(0, &build.config.build);
 
     let favicon = build.src.join("src/doc/favicon.inc");
     let footer = build.src.join("src/doc/footer.inc");
index 6a81f759dc73f8e93203d8093dadbf14b68f1f75..bf815a817ed87c4f2483ef2f74fde47f30561a10 100644 (file)
@@ -365,6 +365,8 @@ fn crate_rule<'a, 'b>(build: &'a Build,
 
         suite("check-rpass-full", "src/test/run-pass-fulldeps",
               "run-pass", "run-pass-fulldeps");
+        suite("check-rfail-full", "src/test/run-fail-fulldeps",
+              "run-fail", "run-fail-fulldeps");
         suite("check-cfail-full", "src/test/compile-fail-fulldeps",
               "compile-fail", "compile-fail-fulldeps");
         suite("check-rmake", "src/test/run-make", "run-make", "run-make");
@@ -459,6 +461,7 @@ fn crate_rule<'a, 'b>(build: &'a Build,
          .dep(|s| s.name("tool-tidy").stage(0))
          .default(true)
          .host(true)
+         .only_build(true)
          .run(move |s| check::tidy(build, s.target));
     rules.test("check-error-index", "src/tools/error_index_generator")
          .dep(|s| s.name("libstd"))
@@ -482,6 +485,12 @@ fn crate_rule<'a, 'b>(build: &'a Build,
          .dep(|s| s.name("libtest"))
          .run(move |s| check::android_copy_libs(build, &s.compiler(), s.target));
 
+    rules.test("check-bootstrap", "src/bootstrap")
+         .default(true)
+         .host(true)
+         .only_build(true)
+         .run(move |_| check::bootstrap(build));
+
     // ========================================================================
     // Build tools
     //
@@ -516,9 +525,14 @@ fn crate_rule<'a, 'b>(build: &'a Build,
          .default(build.config.docs)
          .run(move |s| doc::rustbook(build, s.target, "nomicon"));
     rules.doc("doc-standalone", "src/doc")
-         .dep(move |s| s.name("rustc").host(&build.config.build).target(&build.config.build))
+         .dep(move |s| {
+             s.name("rustc")
+              .host(&build.config.build)
+              .target(&build.config.build)
+              .stage(0)
+         })
          .default(build.config.docs)
-         .run(move |s| doc::standalone(build, s.stage, s.target));
+         .run(move |s| doc::standalone(build, s.target));
     rules.doc("doc-error-index", "src/tools/error_index_generator")
          .dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0))
          .dep(move |s| s.name("librustc-link").stage(0))
@@ -550,6 +564,7 @@ fn crate_rule<'a, 'b>(build: &'a Build,
     rules.dist("dist-rustc", "src/librustc")
          .dep(move |s| s.name("rustc").host(&build.config.build))
          .host(true)
+         .only_host_build(true)
          .default(true)
          .run(move |s| dist::rustc(build, s.stage, s.target));
     rules.dist("dist-std", "src/libstd")
@@ -564,9 +579,11 @@ fn crate_rule<'a, 'b>(build: &'a Build,
              }
          })
          .default(true)
+         .only_host_build(true)
          .run(move |s| dist::std(build, &s.compiler(), s.target));
     rules.dist("dist-mingw", "path/to/nowhere")
          .default(true)
+         .only_host_build(true)
          .run(move |s| {
              if s.target.contains("pc-windows-gnu") {
                  dist::mingw(build, s.target)
@@ -575,14 +592,18 @@ fn crate_rule<'a, 'b>(build: &'a Build,
     rules.dist("dist-src", "src")
          .default(true)
          .host(true)
-         .run(move |s| dist::rust_src(build, s.target));
+         .only_build(true)
+         .only_host_build(true)
+         .run(move |_| dist::rust_src(build));
     rules.dist("dist-docs", "src/doc")
          .default(true)
+         .only_host_build(true)
          .dep(|s| s.name("default:doc"))
          .run(move |s| dist::docs(build, s.stage, s.target));
     rules.dist("dist-analysis", "analysis")
          .dep(|s| s.name("dist-std"))
          .default(true)
+         .only_host_build(true)
          .run(move |s| dist::analysis(build, &s.compiler(), s.target));
     rules.dist("install", "src")
          .dep(|s| s.name("default:dist"))
@@ -671,6 +692,14 @@ struct Rule<'a> {
     /// only intended for compiler hosts and not for targets that are being
     /// generated.
     host: bool,
+
+    /// Whether this rule is only for steps where the host is the build triple,
+    /// not anything in hosts or targets.
+    only_host_build: bool,
+
+    /// Whether this rule is only for the build triple, not anything in hosts or
+    /// targets.
+    only_build: bool,
 }
 
 #[derive(PartialEq)]
@@ -692,6 +721,8 @@ fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> {
             kind: kind,
             default: false,
             host: false,
+            only_host_build: false,
+            only_build: false,
         }
     }
 }
@@ -727,6 +758,16 @@ fn host(&mut self, host: bool) -> &mut Self {
         self.rule.host = host;
         self
     }
+
+    fn only_build(&mut self, only_build: bool) -> &mut Self {
+        self.rule.only_build = only_build;
+        self
+    }
+
+    fn only_host_build(&mut self, only_host_build: bool) -> &mut Self {
+        self.rule.only_host_build = only_host_build;
+        self
+    }
 }
 
 impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
@@ -896,19 +937,12 @@ fn plan(&self) -> Vec<Step<'a>> {
                 path.ends_with(rule.path)
             })
         }).flat_map(|rule| {
-            let hosts = if self.build.flags.host.len() > 0 {
+            let hosts = if rule.only_host_build || rule.only_build {
+                &self.build.config.host[..1]
+            } else if self.build.flags.host.len() > 0 {
                 &self.build.flags.host
             } else {
-                if kind == Kind::Dist {
-                    // For 'dist' steps we only distribute artifacts built from
-                    // the build platform, so only consider that in the hosts
-                    // array.
-                    // NOTE: This relies on the fact that the build triple is
-                    // always placed first, as done in `config.rs`.
-                    &self.build.config.host[..1]
-                } else {
-                    &self.build.config.host
-                }
+                &self.build.config.host
             };
             let targets = if self.build.flags.target.len() > 0 {
                 &self.build.flags.target
@@ -928,6 +962,8 @@ fn plan(&self) -> Vec<Step<'a>> {
                     &self.build.flags.host[..]
                 } else if self.build.flags.target.len() > 0 {
                     &[]
+                } else if rule.only_build {
+                    &self.build.config.host[..1]
                 } else {
                     &self.build.config.host[..]
                 }
@@ -955,12 +991,7 @@ fn run(&self, steps: &[Step<'a>]) {
 
         // Using `steps` as the top-level targets, make a topological ordering
         // of what we need to do.
-        let mut order = Vec::new();
-        let mut added = HashSet::new();
-        added.insert(Step::noop());
-        for step in steps.iter().cloned() {
-            self.fill(step, &mut order, &mut added);
-        }
+        let order = self.expand(steps);
 
         // Print out what we're doing for debugging
         self.build.verbose("bootstrap build plan:");
@@ -979,6 +1010,18 @@ fn run(&self, steps: &[Step<'a>]) {
         }
     }
 
+    /// From the top level targets `steps` generate a topological ordering of
+    /// all steps needed to run those steps.
+    fn expand(&self, steps: &[Step<'a>]) -> Vec<Step<'a>> {
+        let mut order = Vec::new();
+        let mut added = HashSet::new();
+        added.insert(Step::noop());
+        for step in steps.iter().cloned() {
+            self.fill(step, &mut order, &mut added);
+        }
+        return order
+    }
+
     /// Performs topological sort of dependencies rooted at the `step`
     /// specified, pushing all results onto the `order` vector provided.
     ///
@@ -1015,3 +1058,367 @@ fn fill(&self,
         order.push(step);
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use std::env;
+
+    use Build;
+    use config::Config;
+    use flags::Flags;
+
+    macro_rules! a {
+        ($($a:expr),*) => (vec![$($a.to_string()),*])
+    }
+
+    fn build(args: &[&str],
+             extra_host: &[&str],
+             extra_target: &[&str]) -> Build {
+        let mut args = args.iter().map(|s| s.to_string()).collect::<Vec<_>>();
+        args.push("--build".to_string());
+        args.push("A".to_string());
+        let flags = Flags::parse(&args);
+
+        let mut config = Config::default();
+        config.docs = true;
+        config.build = "A".to_string();
+        config.host = vec![config.build.clone()];
+        config.host.extend(extra_host.iter().map(|s| s.to_string()));
+        config.target = config.host.clone();
+        config.target.extend(extra_target.iter().map(|s| s.to_string()));
+
+        let mut build = Build::new(flags, config);
+        let cwd = env::current_dir().unwrap();
+        build.crates.insert("std_shim".to_string(), ::Crate {
+            name: "std_shim".to_string(),
+            deps: Vec::new(),
+            path: cwd.join("src/std_shim"),
+            doc_step: "doc-std_shim".to_string(),
+            build_step: "build-crate-std_shim".to_string(),
+            test_step: "test-std_shim".to_string(),
+            bench_step: "bench-std_shim".to_string(),
+        });
+        build.crates.insert("test_shim".to_string(), ::Crate {
+            name: "test_shim".to_string(),
+            deps: Vec::new(),
+            path: cwd.join("src/test_shim"),
+            doc_step: "doc-test_shim".to_string(),
+            build_step: "build-crate-test_shim".to_string(),
+            test_step: "test-test_shim".to_string(),
+            bench_step: "bench-test_shim".to_string(),
+        });
+        build.crates.insert("rustc-main".to_string(), ::Crate {
+            name: "rustc-main".to_string(),
+            deps: Vec::new(),
+            path: cwd.join("src/rustc-main"),
+            doc_step: "doc-rustc-main".to_string(),
+            build_step: "build-crate-rustc-main".to_string(),
+            test_step: "test-rustc-main".to_string(),
+            bench_step: "bench-rustc-main".to_string(),
+        });
+        return build
+    }
+
+    #[test]
+    fn dist_baseline() {
+        let build = build(&["dist"], &[], &[]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+        assert!(plan.iter().all(|s| s.host == "A" ));
+        assert!(plan.iter().all(|s| s.target == "A" ));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(plan.contains(&step.name("dist-docs")));
+        assert!(plan.contains(&step.name("dist-mingw")));
+        assert!(plan.contains(&step.name("dist-rustc")));
+        assert!(plan.contains(&step.name("dist-std")));
+        assert!(plan.contains(&step.name("dist-src")));
+    }
+
+    #[test]
+    fn dist_with_targets() {
+        let build = build(&["dist"], &[], &["B"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+        assert!(plan.iter().all(|s| s.host == "A" ));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(plan.contains(&step.name("dist-docs")));
+        assert!(plan.contains(&step.name("dist-mingw")));
+        assert!(plan.contains(&step.name("dist-rustc")));
+        assert!(plan.contains(&step.name("dist-std")));
+        assert!(plan.contains(&step.name("dist-src")));
+
+        assert!(plan.contains(&step.target("B").name("dist-docs")));
+        assert!(plan.contains(&step.target("B").name("dist-mingw")));
+        assert!(!plan.contains(&step.target("B").name("dist-rustc")));
+        assert!(plan.contains(&step.target("B").name("dist-std")));
+        assert!(!plan.contains(&step.target("B").name("dist-src")));
+    }
+
+    #[test]
+    fn dist_with_hosts() {
+        let build = build(&["dist"], &["B"], &[]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(!plan.iter().any(|s| s.host == "B"));
+
+        assert!(plan.contains(&step.name("dist-docs")));
+        assert!(plan.contains(&step.name("dist-mingw")));
+        assert!(plan.contains(&step.name("dist-rustc")));
+        assert!(plan.contains(&step.name("dist-std")));
+        assert!(plan.contains(&step.name("dist-src")));
+
+        assert!(plan.contains(&step.target("B").name("dist-docs")));
+        assert!(plan.contains(&step.target("B").name("dist-mingw")));
+        assert!(plan.contains(&step.target("B").name("dist-rustc")));
+        assert!(plan.contains(&step.target("B").name("dist-std")));
+        assert!(!plan.contains(&step.target("B").name("dist-src")));
+    }
+
+    #[test]
+    fn dist_with_targets_and_hosts() {
+        let build = build(&["dist"], &["B"], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(!plan.iter().any(|s| s.host == "B"));
+        assert!(!plan.iter().any(|s| s.host == "C"));
+
+        assert!(plan.contains(&step.name("dist-docs")));
+        assert!(plan.contains(&step.name("dist-mingw")));
+        assert!(plan.contains(&step.name("dist-rustc")));
+        assert!(plan.contains(&step.name("dist-std")));
+        assert!(plan.contains(&step.name("dist-src")));
+
+        assert!(plan.contains(&step.target("B").name("dist-docs")));
+        assert!(plan.contains(&step.target("B").name("dist-mingw")));
+        assert!(plan.contains(&step.target("B").name("dist-rustc")));
+        assert!(plan.contains(&step.target("B").name("dist-std")));
+        assert!(!plan.contains(&step.target("B").name("dist-src")));
+
+        assert!(plan.contains(&step.target("C").name("dist-docs")));
+        assert!(plan.contains(&step.target("C").name("dist-mingw")));
+        assert!(!plan.contains(&step.target("C").name("dist-rustc")));
+        assert!(plan.contains(&step.target("C").name("dist-std")));
+        assert!(!plan.contains(&step.target("C").name("dist-src")));
+    }
+
+    #[test]
+    fn dist_target_with_target_flag() {
+        let build = build(&["dist", "--target=C"], &["B"], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(!plan.iter().any(|s| s.target == "A"));
+        assert!(!plan.iter().any(|s| s.target == "B"));
+        assert!(!plan.iter().any(|s| s.host == "B"));
+        assert!(!plan.iter().any(|s| s.host == "C"));
+
+        assert!(plan.contains(&step.target("C").name("dist-docs")));
+        assert!(plan.contains(&step.target("C").name("dist-mingw")));
+        assert!(!plan.contains(&step.target("C").name("dist-rustc")));
+        assert!(plan.contains(&step.target("C").name("dist-std")));
+        assert!(!plan.contains(&step.target("C").name("dist-src")));
+    }
+
+    #[test]
+    fn dist_host_with_target_flag() {
+        let build = build(&["dist", "--host=B", "--target=B"], &["B"], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        assert!(!plan.iter().any(|s| s.target == "A"));
+        assert!(!plan.iter().any(|s| s.target == "C"));
+        assert!(!plan.iter().any(|s| s.host == "B"));
+        assert!(!plan.iter().any(|s| s.host == "C"));
+
+        assert!(plan.contains(&step.target("B").name("dist-docs")));
+        assert!(plan.contains(&step.target("B").name("dist-mingw")));
+        assert!(plan.contains(&step.target("B").name("dist-rustc")));
+        assert!(plan.contains(&step.target("B").name("dist-std")));
+        assert!(plan.contains(&step.target("B").name("dist-src")));
+
+        let all = rules.expand(&plan);
+        println!("all rules: {:#?}", all);
+        assert!(!all.contains(&step.name("rustc")));
+        assert!(!all.contains(&step.name("build-crate-std_shim").stage(1)));
+    }
+
+    #[test]
+    fn build_default() {
+        let build = build(&["build"], &["B"], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        let step = super::Step {
+            name: "",
+            stage: 2,
+            host: &build.config.build,
+            target: &build.config.build,
+        };
+
+        // rustc built for all for of (A, B) x (A, B)
+        assert!(plan.contains(&step.name("librustc")));
+        assert!(plan.contains(&step.target("B").name("librustc")));
+        assert!(plan.contains(&step.host("B").target("A").name("librustc")));
+        assert!(plan.contains(&step.host("B").target("B").name("librustc")));
+
+        // rustc never built for C
+        assert!(!plan.iter().any(|s| {
+            s.name.contains("rustc") && (s.host == "C" || s.target == "C")
+        }));
+
+        // test built for everything
+        assert!(plan.contains(&step.name("libtest")));
+        assert!(plan.contains(&step.target("B").name("libtest")));
+        assert!(plan.contains(&step.host("B").target("A").name("libtest")));
+        assert!(plan.contains(&step.host("B").target("B").name("libtest")));
+        assert!(plan.contains(&step.host("A").target("C").name("libtest")));
+        assert!(plan.contains(&step.host("B").target("C").name("libtest")));
+
+        let all = rules.expand(&plan);
+        println!("all rules: {:#?}", all);
+        assert!(all.contains(&step.name("rustc")));
+        assert!(all.contains(&step.name("libstd")));
+    }
+
+    #[test]
+    fn build_filtered() {
+        let build = build(&["build", "--target=C"], &["B"], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+
+        assert!(!plan.iter().any(|s| s.name.contains("rustc")));
+        assert!(plan.iter().all(|s| {
+            !s.name.contains("test_shim") || s.target == "C"
+        }));
+    }
+
+    #[test]
+    fn test_default() {
+        let build = build(&["test"], &[], &[]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+        assert!(plan.iter().all(|s| s.host == "A"));
+        assert!(plan.iter().all(|s| s.target == "A"));
+
+        assert!(plan.iter().any(|s| s.name.contains("-ui")));
+        assert!(plan.iter().any(|s| s.name.contains("cfail")));
+        assert!(plan.iter().any(|s| s.name.contains("cfail")));
+        assert!(plan.iter().any(|s| s.name.contains("cfail-full")));
+        assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
+        assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
+        assert!(plan.iter().any(|s| s.name.contains("docs")));
+        assert!(plan.iter().any(|s| s.name.contains("error-index")));
+        assert!(plan.iter().any(|s| s.name.contains("incremental")));
+        assert!(plan.iter().any(|s| s.name.contains("linkchecker")));
+        assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
+        assert!(plan.iter().any(|s| s.name.contains("pfail")));
+        assert!(plan.iter().any(|s| s.name.contains("rfail")));
+        assert!(plan.iter().any(|s| s.name.contains("rfail-full")));
+        assert!(plan.iter().any(|s| s.name.contains("rmake")));
+        assert!(plan.iter().any(|s| s.name.contains("rpass")));
+        assert!(plan.iter().any(|s| s.name.contains("rpass-full")));
+        assert!(plan.iter().any(|s| s.name.contains("rustc-all")));
+        assert!(plan.iter().any(|s| s.name.contains("rustdoc")));
+        assert!(plan.iter().any(|s| s.name.contains("std-all")));
+        assert!(plan.iter().any(|s| s.name.contains("test-all")));
+        assert!(plan.iter().any(|s| s.name.contains("tidy")));
+        assert!(plan.iter().any(|s| s.name.contains("valgrind")));
+    }
+
+    #[test]
+    fn test_with_a_target() {
+        let build = build(&["test", "--target=C"], &[], &["C"]);
+        let rules = super::build_rules(&build);
+        let plan = rules.plan();
+        println!("rules: {:#?}", plan);
+        assert!(plan.iter().all(|s| s.stage == 2));
+        assert!(plan.iter().all(|s| s.host == "A"));
+        assert!(plan.iter().all(|s| s.target == "C"));
+
+        assert!(plan.iter().any(|s| s.name.contains("-ui")));
+        assert!(plan.iter().any(|s| s.name.contains("cfail")));
+        assert!(plan.iter().any(|s| s.name.contains("cfail")));
+        assert!(!plan.iter().any(|s| s.name.contains("cfail-full")));
+        assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
+        assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
+        assert!(!plan.iter().any(|s| s.name.contains("docs")));
+        assert!(!plan.iter().any(|s| s.name.contains("error-index")));
+        assert!(plan.iter().any(|s| s.name.contains("incremental")));
+        assert!(!plan.iter().any(|s| s.name.contains("linkchecker")));
+        assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
+        assert!(plan.iter().any(|s| s.name.contains("pfail")));
+        assert!(plan.iter().any(|s| s.name.contains("rfail")));
+        assert!(!plan.iter().any(|s| s.name.contains("rfail-full")));
+        assert!(!plan.iter().any(|s| s.name.contains("rmake")));
+        assert!(plan.iter().any(|s| s.name.contains("rpass")));
+        assert!(!plan.iter().any(|s| s.name.contains("rpass-full")));
+        assert!(!plan.iter().any(|s| s.name.contains("rustc-all")));
+        assert!(!plan.iter().any(|s| s.name.contains("rustdoc")));
+        assert!(plan.iter().any(|s| s.name.contains("std-all")));
+        assert!(plan.iter().any(|s| s.name.contains("test-all")));
+        assert!(!plan.iter().any(|s| s.name.contains("tidy")));
+        assert!(plan.iter().any(|s| s.name.contains("valgrind")));
+    }
+}
diff --git a/src/ci/docker/dist-arm-unknown-linux-gnueabi/Dockerfile b/src/ci/docker/dist-arm-unknown-linux-gnueabi/Dockerfile
new file mode 100644 (file)
index 0000000..9b0f1b7
--- /dev/null
@@ -0,0 +1,30 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  g++-arm-linux-gnueabi
+
+ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
+RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
+      tar xJf - -C /usr/local/bin --strip-components=1
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+ENV RUST_CONFIGURE_ARGS --host=arm-unknown-linux-gnueabi
+ENV XPY_RUN \
+      dist \
+      --host arm-unknown-linux-gnueabi \
+      --target arm-unknown-linux-gnueabi
diff --git a/src/ci/docker/dist-x86_64-unknown-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-unknown-freebsd/Dockerfile
new file mode 100644 (file)
index 0000000..f1a6ccf
--- /dev/null
@@ -0,0 +1,38 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  bzip2 \
+  xz-utils \
+  wget
+
+COPY build-toolchain.sh /tmp/
+RUN sh /tmp/build-toolchain.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
+RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
+      tar xJf - -C /usr/local/bin --strip-components=1
+
+ENV \
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++
+
+ENV RUST_CONFIGURE_ARGS --host=x86_64-unknown-freebsd
+ENV XPY_RUN \
+      dist \
+      --host x86_64-unknown-freebsd \
+      --target x86_64-unknown-freebsd
diff --git a/src/ci/docker/dist-x86_64-unknown-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-unknown-freebsd/build-toolchain.sh
new file mode 100644 (file)
index 0000000..0fd6bea
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/bash
+# 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.
+
+set -ex
+
+ARCH=x86_64
+BINUTILS=2.25.1
+GCC=5.3.0
+
+mkdir binutils
+cd binutils
+
+# First up, build binutils
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
+mkdir binutils-build
+cd binutils-build
+../binutils-$BINUTILS/configure \
+  --target=$ARCH-unknown-freebsd10
+make -j10
+make install
+cd ../..
+rm -rf binutils
+
+# Next, download the FreeBSD libc and relevant header files
+
+mkdir freebsd
+case "$ARCH" in
+    x86_64)
+        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz
+        ;;
+    i686)
+        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz
+        ;;
+esac
+curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib
+
+dst=/usr/local/$ARCH-unknown-freebsd10
+
+cp -r freebsd/usr/include $dst/
+cp freebsd/usr/lib/crt1.o $dst/lib
+cp freebsd/usr/lib/Scrt1.o $dst/lib
+cp freebsd/usr/lib/crti.o $dst/lib
+cp freebsd/usr/lib/crtn.o $dst/lib
+cp freebsd/usr/lib/libc.a $dst/lib
+cp freebsd/usr/lib/libutil.a $dst/lib
+cp freebsd/usr/lib/libutil_p.a $dst/lib
+cp freebsd/usr/lib/libm.a $dst/lib
+cp freebsd/usr/lib/librt.so.1 $dst/lib
+cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib
+cp freebsd/lib/libc.so.7 $dst/lib
+cp freebsd/lib/libm.so.5 $dst/lib
+cp freebsd/lib/libutil.so.9 $dst/lib
+cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so
+
+ln -s libc.so.7 $dst/lib/libc.so
+ln -s libm.so.5 $dst/lib/libm.so
+ln -s librt.so.1 $dst/lib/librt.so
+ln -s libutil.so.9 $dst/lib/libutil.so
+ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so
+rm -rf freebsd
+
+# Finally, download and build gcc to target FreeBSD
+mkdir gcc
+cd gcc
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+cd gcc-$GCC
+./contrib/download_prerequisites
+
+mkdir ../gcc-build
+cd ../gcc-build
+../gcc-$GCC/configure                            \
+  --enable-languages=c,c++                       \
+  --target=$ARCH-unknown-freebsd10               \
+  --disable-multilib                             \
+  --disable-nls                                  \
+  --disable-libgomp                              \
+  --disable-libquadmath                          \
+  --disable-libssp                               \
+  --disable-libvtv                               \
+  --disable-libcilkrts                           \
+  --disable-libada                               \
+  --disable-libsanitizer                         \
+  --disable-libquadmath-support                  \
+  --disable-lto
+make -j10
+make install
+cd ../..
+rm -rf gcc
diff --git a/src/ci/docker/x86_64-freebsd/Dockerfile b/src/ci/docker/x86_64-freebsd/Dockerfile
deleted file mode 100644 (file)
index 86efa74..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python2.7 \
-  git \
-  cmake \
-  sudo \
-  bzip2 \
-  xz-utils \
-  wget
-
-COPY build-toolchain.sh /tmp/
-RUN sh /tmp/build-toolchain.sh
-
-RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
-    dpkg -i dumb-init_*.deb && \
-    rm dumb-init_*.deb
-ENTRYPOINT ["/usr/bin/dumb-init", "--"]
-
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
-
-ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc
-
-ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd
-ENV RUST_CHECK_TARGET ""
diff --git a/src/ci/docker/x86_64-freebsd/build-toolchain.sh b/src/ci/docker/x86_64-freebsd/build-toolchain.sh
deleted file mode 100644 (file)
index d4bc886..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -ex
-
-ARCH=x86_64
-BINUTILS=2.25.1
-GCC=5.3.0
-
-mkdir binutils
-cd binutils
-
-# First up, build binutils
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
-mkdir binutils-build
-cd binutils-build
-../binutils-$BINUTILS/configure \
-  --target=$ARCH-unknown-freebsd10
-make -j10
-make install
-cd ../..
-rm -rf binutils
-
-# Next, download the FreeBSD libc and relevant header files
-
-mkdir freebsd
-case "$ARCH" in
-    x86_64)
-        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz
-        ;;
-    i686)
-        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz
-        ;;
-esac
-curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib
-
-dst=/usr/local/$ARCH-unknown-freebsd10
-
-cp -r freebsd/usr/include $dst/
-cp freebsd/usr/lib/crt1.o $dst/lib
-cp freebsd/usr/lib/Scrt1.o $dst/lib
-cp freebsd/usr/lib/crti.o $dst/lib
-cp freebsd/usr/lib/crtn.o $dst/lib
-cp freebsd/usr/lib/libc.a $dst/lib
-cp freebsd/usr/lib/libutil.a $dst/lib
-cp freebsd/usr/lib/libutil_p.a $dst/lib
-cp freebsd/usr/lib/libm.a $dst/lib
-cp freebsd/usr/lib/librt.so.1 $dst/lib
-cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib
-cp freebsd/lib/libc.so.7 $dst/lib
-cp freebsd/lib/libm.so.5 $dst/lib
-cp freebsd/lib/libutil.so.9 $dst/lib
-cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so
-
-ln -s libc.so.7 $dst/lib/libc.so
-ln -s libm.so.5 $dst/lib/libm.so
-ln -s librt.so.1 $dst/lib/librt.so
-ln -s libutil.so.9 $dst/lib/libutil.so
-ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so
-rm -rf freebsd
-
-# Finally, download and build gcc to target FreeBSD
-mkdir gcc
-cd gcc
-curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
-cd gcc-$GCC
-./contrib/download_prerequisites
-
-mkdir ../gcc-build
-cd ../gcc-build
-../gcc-$GCC/configure                            \
-  --enable-languages=c                           \
-  --target=$ARCH-unknown-freebsd10               \
-  --disable-multilib                             \
-  --disable-nls                                  \
-  --disable-libgomp                              \
-  --disable-libquadmath                          \
-  --disable-libssp                               \
-  --disable-libvtv                               \
-  --disable-libcilkrts                           \
-  --disable-libada                               \
-  --disable-libsanitizer                         \
-  --disable-libquadmath-support                  \
-  --disable-lto
-make -j10
-make install
-cd ../..
-rm -rf gcc
index 18aa9f24580d5f373855d0fe9da2378a485d38b5..babbafa078f4a7b52c223da7e658c5ba6bd5276d 100644 (file)
@@ -52,6 +52,7 @@
     * [Borrow and AsRef](borrow-and-asref.md)
     * [Release Channels](release-channels.md)
     * [Using Rust without the standard library](using-rust-without-the-standard-library.md)
+    * [Procedural Macros (and custom derive)](procedural-macros.md)
 * [Nightly Rust](nightly-rust.md)
     * [Compiler Plugins](compiler-plugins.md)
     * [Inline Assembly](inline-assembly.md)
diff --git a/src/doc/book/procedural-macros.md b/src/doc/book/procedural-macros.md
new file mode 100644 (file)
index 0000000..37d3d20
--- /dev/null
@@ -0,0 +1,213 @@
+% Procedural Macros (and custom Derive)
+
+As you've seen throughout the rest of the book, Rust provides a mechanism
+called "derive" that lets you implement traits easily. For example,
+
+```rust
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+```
+
+is a lot simpler than
+
+```rust
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+use std::fmt;
+
+impl fmt::Debug for Point {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
+    }
+}
+```
+
+Rust includes several traits that you can derive, but it also lets you define
+your own. We can accomplish this task through a feature of Rust called
+"procedural macros." Eventually, procedural macros will allow for all sorts of
+advanced metaprogramming in Rust, but today, they're only for custom derive.
+
+Let's build a very simple trait, and derive it with custom derive.
+
+## Hello World
+
+So the first thing we need to do is start a new crate for our project.
+
+```bash
+$ cargo new --bin hello-world
+```
+
+All we want is to be able to call `hello_world()` on a derived type. Something
+like this:
+
+```rust,ignore
+#[derive(HelloWorld)]
+struct Pancakes;
+
+fn main() {
+    Pancakes::hello_world();
+}
+```
+
+With some kind of nice output, like `Hello, World! My name is Pancakes.`. 
+
+Let's go ahead and write up what we think our macro will look like from a user
+perspective. In `src/main.rs` we write:
+
+```rust,ignore
+#[macro_use]
+extern crate hello_world_derive;
+
+trait HelloWorld {
+    fn hello_world();
+}
+
+#[derive(HelloWorld)]
+struct FrenchToast;
+
+#[derive(HelloWorld)]
+struct Waffles;
+
+fn main() {
+    FrenchToast::hello_world();
+    Waffles::hello_world();
+}
+```
+
+Great. So now we just need to actually write the procedural macro. At the
+moment, procedural macros need to be in their own crate. Eventually, this
+restriction may be lifted, but for now, it's required. As such, there's a
+convention; for a crate named `foo`, a custom derive procedural macro is called
+`foo-derive`. Let's start a new crate called `hello-world-derive` inside our
+`hello-world` project.
+
+```bash
+$ cargo new hello-world-derive
+```
+
+To make sure that our `hello-world` crate is able to find this new crate we've
+created, we'll add it to our toml:
+
+```toml
+[dependencies]
+hello-world-derive = { path = "hello-world-derive" }
+```
+
+As for our the source of our `hello-world-derive` crate, here's an example:
+
+```rust,ignore
+extern crate proc_macro;
+extern crate syn;
+#[macro_use]
+extern crate quote;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(HelloWorld)]
+pub fn hello_world(input: TokenStream) -> TokenStream {
+    // Construct a string representation of the type definition
+    let s = input.to_string();
+    
+    // Parse the string representation
+    let ast = syn::parse_macro_input(&s).unwrap();
+
+    // Build the impl
+    let gen = impl_hello_world(&ast);
+    
+    // Return the generated impl
+    gen.parse().unwrap()
+}
+```
+
+So there is a lot going on here. We have introduced two new crates: [`syn`] and
+[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
+to a `String`. This `String` is a string representation of the Rust code for which
+we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
+`TokenStream` is convert it to a string. A richer API will exist in the future.
+
+So what we really need is to be able to _parse_ Rust code into something
+usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust
+code. The other crate we've introduced is `quote`. It's essentially the dual of
+`syn` as it will make generating Rust code really easy. We could write this
+stuff on our own, but it's much simpler to use these libraries. Writing a full
+parser for Rust code is no simple task.
+
+[`syn`]: https://crates.io/crates/syn
+[`quote`]: https://crates.io/crates/quote
+
+The comments seem to give us a pretty good idea of our overall strategy. We
+are going to take a `String` of the Rust code for the type we are deriving, parse
+it using `syn`, construct the implementation of `hello_world` (using `quote`),
+then pass it back to Rust compiler.
+
+One last note: you'll see some `unwrap()`s there. If you want to provide an
+error for a procedural macro, then you should `panic!` with the error message.
+In this case, we're keeping it as simple as possible.
+
+Great, so let's write `impl_hello_world(&ast)`.
+
+```rust,ignore
+fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
+    let name = &ast.ident;
+    quote! {
+        impl HelloWorld for #name {
+            fn hello_world() {
+                println!("Hello, World! My name is {}", stringify!(#name));
+            }
+        }
+    }
+}
+```
+
+So this is where quotes comes in. The `ast` argument is a struct that gives us
+a representation of our type (which can be either a `struct` or an `enum`).
+Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
+there is some useful information there. We are able to get the name of the
+type using `ast.ident`. The `quote!` macro let's us write up the Rust code
+that we wish to return and convert it into `Tokens`. `quote!` let's us use some
+really cool templating mechanics; we simply write `#name` and `quote!` will
+replace it with the variable named `name`. You can even do some repetition
+similar to regular macros work. You should check out the
+[docs](https://docs.rs/quote) for a good introduction.
+
+So I think that's it. Oh, well, we do need to add dependencies for `syn` and
+`quote` in the `cargo.toml` for `hello-world-derive`.
+
+```toml
+[dependencies]
+syn = "0.10.5"
+quote = "0.3.10"
+```
+
+That should be it. Let's try to compile `hello-world`.
+
+```bash
+error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
+ --> hello-world-derive/src/lib.rs:8:3
+  |
+8 | #[proc_macro_derive(HelloWorld)]
+  |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+```
+
+Oh, so it appears that we need to declare that our `hello-world-derive` crate is
+a `proc-macro` crate type. How do we do this? Like this:
+
+```toml
+[lib]
+proc-macro = true
+```
+
+Ok so now, let's compile `hello-world`. Executing `cargo run` now yields:
+
+```bash
+Hello, World! My name is FrenchToast
+Hello, World! My name is Waffles
+```
+
+We've done it!
index 6af15d8768363bd947d8f73b589dec852436fe77..a2146b669e3c6d65dfad480a03e89106326af2fc 100644 (file)
@@ -163,8 +163,8 @@ let hachi = &dog[0..2];
 with this error:
 
 ```text
-thread 'main' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on
-character boundary'
+thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '忠'
+(bytes 0..3) of `忠犬ハチ公`'
 ```
 
 ## Concatenation
index 1efca08abd094d7b6833a2e4ff47f6a41aed4b23..7b4c44ff051d626d1789e29e3e94424018b7253f 100644 (file)
@@ -24,10 +24,10 @@ exactly what we said but, you know, fast. Wouldn't that be great?
 
 # Compiler Reordering
 
-Compilers fundamentally want to be able to do all sorts of crazy transformations
-to reduce data dependencies and eliminate dead code. In particular, they may
-radically change the actual order of events, or make events never occur! If we
-write something like
+Compilers fundamentally want to be able to do all sorts of complicated
+transformations to reduce data dependencies and eliminate dead code. In
+particular, they may radically change the actual order of events, or make events
+never occur! If we write something like
 
 ```rust,ignore
 x = 1;
index 978d0518729ea5705e37c19834a41b6337fb0e42..15d84fdbf29371855e9448f89e41ac8ea7161244 100644 (file)
@@ -22,7 +22,7 @@ Well, Rust *has* a safe programming language. Let's step back a bit.
 Rust can be thought of as being composed of two programming languages: *Safe
 Rust* and *Unsafe Rust*. Safe Rust is For Reals  Totally Safe. Unsafe Rust,
 unsurprisingly, is *not* For Reals Totally Safe.  In fact, Unsafe Rust lets you
-do some really crazy unsafe things.
+do some really, *really* unsafe things.
 
 Safe Rust is the *true* Rust programming language. If all you do is write Safe
 Rust, you will never have to worry about type-safety or memory-safety. You will
index f0732cf26562cf21459a5fc8bcffa574fc5d8386..5145987158abc04d95afbcc85b29c59e8cc69532 100644 (file)
@@ -21,11 +21,11 @@ prevent *all* race conditions would be pretty awful to use, if not just
 incorrect.
 
 So it's perfectly "fine" for a Safe Rust program to get deadlocked or do
-something incredibly stupid with incorrect synchronization. Obviously such a
-program isn't very good, but Rust can only hold your hand so far. Still, a
-race condition can't violate memory safety in a Rust program on
-its own. Only in conjunction with some other unsafe code can a race condition
-actually violate memory safety. For instance:
+something nonsensical with incorrect synchronization. Obviously such a program
+isn't very good, but Rust can only hold your hand so far. Still, a race
+condition can't violate memory safety in a Rust program on its own. Only in
+conjunction with some other unsafe code can a race condition actually violate
+memory safety. For instance:
 
 ```rust,no_run
 use std::thread;
index 9898c31282c34949aa13db715c5b6b27ed12c907..4112b328f612ee380416aebe5763036126ea7efa 100644 (file)
@@ -555,26 +555,24 @@ mod a {
 # fn main() {}
 ```
 
-# Syntax extensions
+# Macros
 
 A number of minor features of Rust are not central enough to have their own
 syntax, and yet are not implementable as functions. Instead, they are given
 names, and invoked through a consistent syntax: `some_extension!(...)`.
 
-Users of `rustc` can define new syntax extensions in two ways:
-
-* [Compiler plugins][plugin] can include arbitrary Rust code that
-  manipulates syntax trees at compile time. Note that the interface
-  for compiler plugins is considered highly unstable.
+Users of `rustc` can define new macros in two ways:
 
 * [Macros](book/macros.html) define new syntax in a higher-level,
   declarative way.
+* [Procedural Macros][procedural macros] can be used to implement custom derive.
+
+And one unstable way: [compiler plugins][plugin].
 
 ## Macros
 
 `macro_rules` allows users to define syntax extension in a declarative way.  We
-call such extensions "macros by example" or simply "macros" — to be distinguished
-from the "procedural macros" defined in [compiler plugins][plugin].
+call such extensions "macros by example" or simply "macros".
 
 Currently, macros can expand to expressions, statements, items, or patterns.
 
@@ -652,6 +650,28 @@ Rust syntax is restricted in two ways:
 
 [RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md
 
+## Procedrual Macros
+
+"Procedrual macros" are the second way to implement a macro. For now, the only
+thing they can be used for is to implement derive on your own types. See
+[the book][procedural macros] for a tutorial.
+
+Procedural macros involve a few different parts of the language and its
+standard libraries. First is the `proc_macro` crate, included with Rust,
+that defines an interface for building a procedrual macro. The 
+`#[proc_macro_derive(Foo)]` attribute is used to mark the the deriving
+function. This function must have the type signature:
+
+```rust,ignore
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Hello)]
+pub fn hello_world(input: TokenStream) -> TokenStream
+```
+
+Finally, procedural macros must be in their own crate, with the `proc-macro`
+crate type.
+
 # Crates and source files
 
 Although Rust, like any other language, can be implemented by an interpreter as
@@ -2319,6 +2339,9 @@ impl<T: PartialEq> PartialEq for Foo<T> {
 }
 ```
 
+You can implement `derive` for your own type through [procedural
+macros](#procedural-macros).
+
 ### Compiler Features
 
 Certain aspects of Rust may be implemented in the compiler, but they're not
@@ -4122,6 +4145,16 @@ be ignored in favor of only building the artifacts specified by command line.
   in dynamic libraries. This form of output is used to produce statically linked
   executables as well as `staticlib` outputs.
 
+* `--crate-type=proc-macro`, `#[crate_type = "proc-macro"]` - The output
+  produced is not specified, but if a `-L` path is provided to it then the
+  compiler will recognize the output artifacts as a macro and it can be loaded
+  for a program. If a crate is compiled with the `proc-macro` crate type it
+  will forbid exporting any items in the crate other than those functions
+  tagged `#[proc_macro_derive]` and those functions must also be placed at the
+  crate root. Finally, the compiler will automatically set the
+  `cfg(proc_macro)` annotation whenever any crate type of a compilation is the
+  `proc-macro` crate type.
+
 Note that these outputs are stackable in the sense that if multiple are
 specified, then the compiler will produce each form of output at once without
 having to recompile. However, this only applies for outputs specified by the
@@ -4299,3 +4332,4 @@ that have since been removed):
 
 [ffi]: book/ffi.html
 [plugin]: book/compiler-plugins.html
+[procedural macros]: book/procedural-macros.html
index eb562877c85732702a0d449808f67f4d463fd030..5e3ff5246a922d3089b06d5859a39cbd0014224a 100644 (file)
@@ -45,6 +45,7 @@ TYPE_KIND_SINGLETON_ENUM    = 13
 TYPE_KIND_CSTYLE_ENUM       = 14
 TYPE_KIND_PTR               = 15
 TYPE_KIND_FIXED_SIZE_VEC    = 16
+TYPE_KIND_REGULAR_UNION     = 17
 
 ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
 ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
@@ -188,15 +189,18 @@ class Type(object):
         union_member_count = len(union_members)
         if union_member_count == 0:
             return TYPE_KIND_EMPTY
-        elif union_member_count == 1:
-            first_variant_name = union_members[0].name
-            if first_variant_name is None:
+
+        first_variant_name = union_members[0].name
+        if first_variant_name is None:
+            if union_member_count == 1:
                 return TYPE_KIND_SINGLETON_ENUM
             else:
-                assert first_variant_name.startswith(ENCODED_ENUM_PREFIX)
-                return TYPE_KIND_COMPRESSED_ENUM
+                return TYPE_KIND_REGULAR_ENUM
+        elif first_variant_name.startswith(ENCODED_ENUM_PREFIX):
+            assert union_member_count == 1
+            return TYPE_KIND_COMPRESSED_ENUM
         else:
-            return TYPE_KIND_REGULAR_ENUM
+            return TYPE_KIND_REGULAR_UNION
 
 
     def __conforms_to_field_layout(self, expected_fields):
index 335acae5fb6f7df5817da3b5a14b6bfb4f539f4e..4427313f9e5b352b55bbabc9e6ff4b3a2a16548d 100644 (file)
@@ -90,6 +90,7 @@ def print_val(lldb_val, internal_dict):
     type_kind = val.type.get_type_kind()
 
     if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or
+        type_kind == rustpp.TYPE_KIND_REGULAR_UNION or
         type_kind == rustpp.TYPE_KIND_EMPTY):
         return print_struct_val(val,
                                 internal_dict,
@@ -175,7 +176,8 @@ def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tu
     Prints a struct, tuple, or tuple struct value with Rust syntax.
     Ignores any fields before field_start_index.
     """
-    assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT
+    assert (val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT or
+            val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION)
 
     if omit_type_name:
         type_name = ""
index 384579ce6b8b46af7ef6feb7bc2aba6f42ee8f47..5e685847e3c81afcee49be68bf9b9570addde49b 100644 (file)
@@ -383,17 +383,29 @@ fn test_is_char_boundary() {
 
 // check the panic includes the prefix of the sliced string
 #[test]
-#[should_panic(expected="Lorem ipsum dolor sit amet")]
+#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
 fn test_slice_fail_truncated_1() {
     &LOREM_PARAGRAPH[..1024];
 }
 // check the truncation in the panic message
 #[test]
-#[should_panic(expected="luctus, im`[...] do not lie on character boundary")]
+#[should_panic(expected="luctus, im`[...]")]
 fn test_slice_fail_truncated_2() {
     &LOREM_PARAGRAPH[..1024];
 }
 
+#[test]
+#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
+fn test_slice_fail_boundary_1() {
+    &"abcαβγ"[4..];
+}
+
+#[test]
+#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
+fn test_slice_fail_boundary_2() {
+    &"abcαβγ"[2..6];
+}
+
 #[test]
 fn test_slice_from() {
     assert_eq!(&"abcd"[0..], "abcd");
index 9af10966eda4bc8e9bc81a5ab96955918e679886..ed01b93f1335a3289c52e656ce105166b3e6b940 100644 (file)
@@ -234,12 +234,10 @@ pub trait Unsize<T: ?Sized> {
 /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's
 /// managing some resource besides its own [`size_of::<T>()`] bytes.
 ///
-/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
-/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
-/// [E0205].
+/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get
+/// the error [E0204].
 ///
 /// [E0204]: ../../error-index.html#E0204
-/// [E0205]: ../../error-index.html#E0205
 ///
 /// ## When *should* my type be `Copy`?
 ///
index de418b831cc8842f0061c6df8319c2fdf26eebc7..db46bd00c8bc1720302810fe6057f626f6e4877c 100644 (file)
@@ -1746,13 +1746,31 @@ fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
 #[cold]
 fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     const MAX_DISPLAY_LENGTH: usize = 256;
-    let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
+    let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
     let ellipsis = if truncated { "[...]" } else { "" };
 
+    // 1. out of bounds
+    if begin > s.len() || end > s.len() {
+        let oob_index = if begin > s.len() { begin } else { end };
+        panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
+    }
+
+    // 2. begin <= end
     assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}",
-            begin, end, s, ellipsis);
-    panic!("index {} and/or {} in `{}`{} do not lie on character boundary",
-          begin, end, s, ellipsis);
+            begin, end, s_trunc, ellipsis);
+
+    // 3. character boundary
+    let index = if !s.is_char_boundary(begin) { begin } else { end };
+    // find the character
+    let mut char_start = index;
+    while !s.is_char_boundary(char_start) {
+        char_start -= 1;
+    }
+    // `char_start` must be less than len and a char boundary
+    let ch = s[char_start..].chars().next().unwrap();
+    let char_range = char_start .. char_start + ch.len_utf8();
+    panic!("byte index {} is not a char boundary; it is inside {:?} (bytes {:?}) of `{}`{}",
+           index, ch, char_range, s_trunc, ellipsis);
 }
 
 #[stable(feature = "core", since = "1.6.0")]
index 98589876259e19f13eab81b033ced95bbb6deca0..7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0
+Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc
index 5ee9fecfb21b3ce0d9b70aead5a85a72da01c546..22b365fa64f0eba966998432a5a045370d47872d 100644 (file)
 //! Currently the primary use of this crate is to provide the ability to define
 //! new custom derive modes through `#[proc_macro_derive]`.
 //!
-//! Added recently as part of [RFC 1681] this crate is currently *unstable* and
-//! requires the `#![feature(proc_macro_lib)]` directive to use.
-//!
-//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
-//!
 //! Note that this crate is intentionally very bare-bones currently. The main
 //! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
 //! implementations, indicating that it can only go to and come from a string.
 //! This functionality is intended to be expanded over time as more surface
 //! area for macro authors is stabilized.
+//!
+//! See [the book](../../book/procedural-macros.html) for more.
 
 #![crate_name = "proc_macro"]
-#![unstable(feature = "proc_macro_lib", issue = "27812")]
+#![stable(feature = "proc_macro_lib", since = "1.15.0")]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![cfg_attr(not(stage0), deny(warnings))]
 ///
 /// The API of this type is intentionally bare-bones, but it'll be expanded over
 /// time!
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 pub struct TokenStream {
     inner: Vec<P<ast::Item>>,
 }
 
 /// Error returned from `TokenStream::from_str`.
 #[derive(Debug)]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 pub struct LexError {
     _inner: (),
 }
@@ -131,6 +130,7 @@ pub fn with_parse_sess<F, R>(f: F) -> R
     }
 }
 
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl FromStr for TokenStream {
     type Err = LexError;
 
@@ -154,6 +154,7 @@ fn from_str(src: &str) -> Result<TokenStream, LexError> {
     }
 }
 
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl fmt::Display for TokenStream {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         for item in self.inner.iter() {
index 9ff7dcc7d58835beaface33b9cf59205fda0a0b6..095d2a78a94cd993e0b5a0597f07f50006404afc 100644 (file)
@@ -113,6 +113,22 @@ fn item_scope_tag(item: &hir::Item) -> &'static str {
             }
         }
 
+        fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str {
+            match item.node {
+                hir::TraitItemKind::Method(..) => "method body",
+                hir::TraitItemKind::Const(..) |
+                hir::TraitItemKind::Type(..) => "associated item"
+            }
+        }
+
+        fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
+            match item.node {
+                hir::ImplItemKind::Method(..) => "method body",
+                hir::ImplItemKind::Const(..) |
+                hir::ImplItemKind::Type(_) => "associated item"
+            }
+        }
+
         fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                         heading: &str, span: Span)
                                         -> (String, Option<Span>) {
@@ -148,6 +164,8 @@ fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     },
                     Some(ast_map::NodeStmt(_)) => "statement",
                     Some(ast_map::NodeItem(it)) => item_scope_tag(&it),
+                    Some(ast_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
+                    Some(ast_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
                     Some(_) | None => {
                         err.span_note(span, &unknown_scope());
                         return;
@@ -186,23 +204,31 @@ fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     }
                 };
 
-                match self.map.find(fr.scope.node_id(&self.region_maps)) {
-                    Some(ast_map::NodeBlock(ref blk)) => {
-                        let (msg, opt_span) = explain_span(self, "block", blk.span);
-                        (format!("{} {}", prefix, msg), opt_span)
-                    }
-                    Some(ast_map::NodeItem(it)) => {
-                        let tag = item_scope_tag(&it);
-                        let (msg, opt_span) = explain_span(self, tag, it.span);
-                        (format!("{} {}", prefix, msg), opt_span)
+                let node = fr.scope.node_id(&self.region_maps);
+                let unknown;
+                let tag = match self.map.find(node) {
+                    Some(ast_map::NodeBlock(_)) |
+                    Some(ast_map::NodeExpr(_)) => "body",
+                    Some(ast_map::NodeItem(it)) => item_scope_tag(&it),
+                    Some(ast_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
+                    Some(ast_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
+
+                    // this really should not happen, but it does:
+                    // FIXME(#27942)
+                    Some(_) => {
+                        unknown = format!("unexpected node ({}) for scope {:?}.  \
+                                           Please report a bug.",
+                                          self.map.node_to_string(node), fr.scope);
+                        &unknown
                     }
-                    Some(_) | None => {
-                        // this really should not happen, but it does:
-                        // FIXME(#27942)
-                        (format!("{} unknown free region bounded by scope {:?}",
-                                 prefix, fr.scope), None)
+                    None => {
+                        unknown = format!("unknown node for scope {:?}.  \
+                                           Please report a bug.", fr.scope);
+                        &unknown
                     }
-                }
+                };
+                let (msg, opt_span) = explain_span(self, tag, self.map.span(node));
+                (format!("{} {}", prefix, msg), opt_span)
             }
 
             ty::ReStatic => ("the static lifetime".to_owned(), None),
index 667c2590fa9966d7b6f539fc70c5ad5849f15dfd..96fb168581b2169ee141d09a22cf9280c50a4155 100644 (file)
     "detects unreachable code paths"
 }
 
+declare_lint! {
+    pub UNREACHABLE_PATTERNS,
+    Warn,
+    "detects unreachable patterns"
+}
+
 declare_lint! {
     pub WARNINGS,
     Warn,
@@ -239,6 +245,7 @@ fn get_lints(&self) -> LintArray {
             UNUSED_ASSIGNMENTS,
             DEAD_CODE,
             UNREACHABLE_CODE,
+            UNREACHABLE_PATTERNS,
             WARNINGS,
             UNUSED_FEATURES,
             STABLE_FEATURES,
index 76adee4e00c15684ec411deddddf5daa2232cb45..00e21410c707757d5ab28930b017ecec0aea65b8 100644 (file)
@@ -445,6 +445,11 @@ fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool {
             && !has_allow_dead_code_or_lang_attr(&variant.attrs)
     }
 
+    fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool {
+        !self.symbol_is_live(fi.id, None)
+            && !has_allow_dead_code_or_lang_attr(&fi.attrs)
+    }
+
     // id := node id of an item's definition.
     // ctor_id := `Some` if the item is a struct_ctor (tuple struct),
     //            `None` otherwise.
@@ -534,7 +539,7 @@ fn visit_variant(&mut self,
     }
 
     fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
-        if !self.symbol_is_live(fi.id, None) {
+        if self.should_warn_about_foreign_item(fi) {
             self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
         }
         intravisit::walk_foreign_item(self, fi);
index f45e86f2f4b9615d32aae1b8c51fb41adf328ff2..e6c9d2c36d013fa9d9677e260534b0148605d1be 100644 (file)
@@ -18,7 +18,7 @@
 use lint;
 use hir::def::Def;
 use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE};
-use ty::TyCtxt;
+use ty::{self, TyCtxt};
 use middle::privacy::AccessLevels;
 use syntax::symbol::Symbol;
 use syntax_pos::{Span, DUMMY_SP};
@@ -432,6 +432,36 @@ struct Checker<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    // (See issue #38412)
+    fn skip_stability_check_due_to_privacy(self, def_id: DefId) -> bool {
+        let visibility = {
+            // Check if `def_id` is a trait method.
+            match self.sess.cstore.associated_item(def_id) {
+                Some(ty::AssociatedItem { container: ty::TraitContainer(trait_def_id), .. }) => {
+                    // Trait methods do not declare visibility (even
+                    // for visibility info in cstore). Use containing
+                    // trait instead, so methods of pub traits are
+                    // themselves considered pub.
+                    self.sess.cstore.visibility(trait_def_id)
+                }
+                _ => {
+                    // Otherwise, cstore info works directly.
+                    self.sess.cstore.visibility(def_id)
+                }
+            }
+        };
+
+        match visibility {
+            // must check stability for pub items.
+            ty::Visibility::Public => false,
+
+            // these are not visible outside crate; therefore
+            // stability markers are irrelevant, if even present.
+            ty::Visibility::Restricted(..) |
+            ty::Visibility::Invisible => true,
+        }
+    }
+
     pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) {
         if self.sess.codemap().span_allows_unstable(span) {
             debug!("stability: \
@@ -492,6 +522,11 @@ pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) {
             self.stability.borrow_mut().used_features.insert(feature.clone(), level.clone());
         }
 
+        // Issue 38412: private items lack stability markers.
+        if self.skip_stability_check_due_to_privacy(def_id) {
+            return
+        }
+
         match stability {
             Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
                 if !self.stability.borrow().active_features.contains(feature) {
index 3cd35804732926d9689679b5c5d0dde745b6406b..1d0e95245ea2dd31793a14079f3b145b0326b7cb 100644 (file)
@@ -888,6 +888,10 @@ pub fn deref(self) -> Lvalue<'tcx> {
         self.elem(ProjectionElem::Deref)
     }
 
+    pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: usize) -> Lvalue<'tcx> {
+        self.elem(ProjectionElem::Downcast(adt_def, variant_index))
+    }
+
     pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
         self.elem(ProjectionElem::Index(index))
     }
index b3cb5ace45bc04e702d8b16a506f48f1b9277cea..59bc001516c79f9b889f7d56fdeef566bcc85bd2 100644 (file)
@@ -1182,7 +1182,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                               the compiler to emit",
                  "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info]"),
         opt::multi_s("", "print", "Comma separated list of compiler information to \
-                               print on stdout", &print_opts.join("|")),
+                               print on stdout", &format!("[{}]",
+                               &print_opts.join("|"))),
         opt::flagmulti_s("g",  "",  "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
index f58d7dcb45f3043193d5b65652c79ff5f452002c..644df8741e8534a472cde67a54e34782352235df 100644 (file)
@@ -33,6 +33,7 @@
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
+use ty::inhabitedness::DefIdForest;
 use ty::maps;
 use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
@@ -459,6 +460,8 @@ pub struct GlobalCtxt<'tcx> {
     // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
+    pub inhabitedness_cache: RefCell<FxHashMap<Ty<'tcx>, DefIdForest>>,
+
     pub lang_items: middle::lang_items::LanguageItems,
 
     /// Maps from def-id of a type or region parameter to its
@@ -760,6 +763,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FxHashMap()),
+            inhabitedness_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
             inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             used_unsafe: RefCell::new(NodeSet()),
diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs
new file mode 100644 (file)
index 0000000..16bc656
--- /dev/null
@@ -0,0 +1,133 @@
+// 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 std::mem;
+use rustc_data_structures::small_vec::SmallVec;
+use syntax::ast::CRATE_NODE_ID;
+use ty::context::TyCtxt;
+use ty::{DefId, DefIdTree};
+
+/// Represents a forest of DefIds closed under the ancestor relation. That is,
+/// if a DefId representing a module is contained in the forest then all
+/// DefIds defined in that module or submodules are also implicitly contained
+/// in the forest.
+///
+/// This is used to represent a set of modules in which a type is visibly
+/// uninhabited.
+#[derive(Clone)]
+pub struct DefIdForest {
+    /// The minimal set of DefIds required to represent the whole set.
+    /// If A and B are DefIds in the DefIdForest, and A is a desecendant
+    /// of B, then only B will be in root_ids.
+    /// We use a SmallVec here because (for its use for cacheing inhabitedness)
+    /// its rare that this will contain even two ids.
+    root_ids: SmallVec<[DefId; 1]>,
+}
+
+impl<'a, 'gcx, 'tcx> DefIdForest {
+    /// Create an empty forest.
+    pub fn empty() -> DefIdForest {
+        DefIdForest {
+            root_ids: SmallVec::new(),
+        }
+    }
+
+    /// Create a forest consisting of a single tree representing the entire
+    /// crate.
+    #[inline]
+    pub fn full(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest {
+        let crate_id = tcx.map.local_def_id(CRATE_NODE_ID);
+        DefIdForest::from_id(crate_id)
+    }
+
+    /// Create a forest containing a DefId and all its descendants.
+    pub fn from_id(id: DefId) -> DefIdForest {
+        let mut root_ids = SmallVec::new();
+        root_ids.push(id);
+        DefIdForest {
+            root_ids: root_ids,
+        }
+    }
+
+    /// Test whether the forest is empty.
+    pub fn is_empty(&self) -> bool {
+        self.root_ids.is_empty()
+    }
+
+    /// Test whether the forest conains a given DefId.
+    pub fn contains(&self,
+                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                    id: DefId) -> bool
+    {
+        for root_id in self.root_ids.iter() {
+            if tcx.is_descendant_of(id, *root_id) {
+                return true;
+            }
+        }
+        false
+    }
+
+    /// Calculate the intersection of a collection of forests.
+    pub fn intersection<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                           iter: I) -> DefIdForest
+            where I: IntoIterator<Item=DefIdForest>
+    {
+        let mut ret = DefIdForest::full(tcx);
+        let mut next_ret = SmallVec::new();
+        let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
+        for next_forest in iter {
+            for id in ret.root_ids.drain(..) {
+                if next_forest.contains(tcx, id) {
+                    next_ret.push(id);
+                } else {
+                    old_ret.push(id);
+                }
+            }
+            ret.root_ids.extend(old_ret.drain(..));
+
+            for id in next_forest.root_ids {
+                if ret.contains(tcx, id) {
+                    next_ret.push(id);
+                }
+            }
+
+            mem::swap(&mut next_ret, &mut ret.root_ids);
+            next_ret.drain(..);
+        }
+        ret
+    }
+
+    /// Calculate the union of a collection of forests.
+    pub fn union<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                    iter: I) -> DefIdForest
+            where I: IntoIterator<Item=DefIdForest>
+    {
+        let mut ret = DefIdForest::empty();
+        let mut next_ret = SmallVec::new();
+        for next_forest in iter {
+            for id in ret.root_ids.drain(..) {
+                if !next_forest.contains(tcx, id) {
+                    next_ret.push(id);
+                }
+            }
+
+            for id in next_forest.root_ids {
+                if !next_ret.contains(&id) {
+                    next_ret.push(id);
+                }
+            }
+
+            mem::swap(&mut next_ret, &mut ret.root_ids);
+            next_ret.drain(..);
+        }
+        ret
+    }
+}
+
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
new file mode 100644 (file)
index 0000000..c5b7583
--- /dev/null
@@ -0,0 +1,199 @@
+// 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 util::nodemap::FxHashSet;
+use ty::context::TyCtxt;
+use ty::{AdtDef, VariantDef, FieldDef, TyS};
+use ty::{DefId, Substs};
+use ty::{AdtKind, Visibility};
+use ty::TypeVariants::*;
+
+pub use self::def_id_forest::DefIdForest;
+
+mod def_id_forest;
+
+// The methods in this module calculate DefIdForests of modules in which a
+// AdtDef/VariantDef/FieldDef is visibly uninhabited.
+//
+// # Example
+// ```rust
+// enum Void {}
+// mod a {
+//     pub mod b {
+//         pub struct SecretlyUninhabited {
+//             _priv: !,
+//         }
+//     }
+// }
+//
+// mod c {
+//     pub struct AlsoSecretlyUninhabited {
+//         _priv: Void,
+//     }
+//     mod d {
+//     }
+// }
+//
+// struct Foo {
+//     x: a::b::SecretlyUninhabited,
+//     y: c::AlsoSecretlyUninhabited,
+// }
+// ```
+// In this code, the type Foo will only be visibly uninhabited inside the
+// modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will
+// return the forest of modules {b, c->d} (represented in a DefIdForest by the
+// set {b, c})
+//
+// We need this information for pattern-matching on Foo or types that contain
+// Foo.
+//
+// # Example
+// ```rust
+// let foo_result: Result<T, Foo> = ... ;
+// let Ok(t) = foo_result;
+// ```
+// This code should only compile in modules where the uninhabitedness of Foo is
+// visible.
+
+impl<'a, 'gcx, 'tcx> AdtDef {
+    /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
+    pub fn uninhabited_from(
+                &self,
+                visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                substs: &'tcx Substs<'tcx>) -> DefIdForest
+    {
+        if !visited.insert((self.did, substs)) {
+            return DefIdForest::empty();
+        }
+
+        let ret = DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
+            v.uninhabited_from(visited, tcx, substs, self.adt_kind())
+        }));
+        visited.remove(&(self.did, substs));
+        ret
+    }
+}
+
+impl<'a, 'gcx, 'tcx> VariantDef {
+    /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
+    pub fn uninhabited_from(
+                &self,
+                visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                substs: &'tcx Substs<'tcx>,
+                adt_kind: AdtKind) -> DefIdForest
+    {
+        match adt_kind {
+            AdtKind::Union => {
+                DefIdForest::intersection(tcx, self.fields.iter().map(|f| {
+                    f.uninhabited_from(visited, tcx, substs, false)
+                }))
+            },
+            AdtKind::Struct => {
+                DefIdForest::union(tcx, self.fields.iter().map(|f| {
+                    f.uninhabited_from(visited, tcx, substs, false)
+                }))
+            },
+            AdtKind::Enum => {
+                DefIdForest::union(tcx, self.fields.iter().map(|f| {
+                    f.uninhabited_from(visited, tcx, substs, true)
+                }))
+            },
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> FieldDef {
+    /// Calculate the forest of DefIds from which this field is visibly uninhabited.
+    pub fn uninhabited_from(
+                &self,
+                visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                substs: &'tcx Substs<'tcx>,
+                is_enum: bool) -> DefIdForest
+    {
+        let mut data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(visited, tcx);
+        // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
+        // Visibility::Invisible so we need to override self.vis if we're
+        // dealing with an enum.
+        if is_enum {
+            data_uninhabitedness()
+        } else {
+            match self.vis {
+                Visibility::Invisible => DefIdForest::empty(),
+                Visibility::Restricted(from) => {
+                    let forest = DefIdForest::from_id(from);
+                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
+                    DefIdForest::intersection(tcx, iter)
+                },
+                Visibility::Public => data_uninhabitedness(),
+            }
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TyS<'tcx> {
+    /// Calculate the forest of DefIds from which this type is visibly uninhabited.
+    pub fn uninhabited_from(
+                &self,
+                visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
+    {
+        match tcx.lift_to_global(&self) {
+            Some(global_ty) => {
+                {
+                    let cache = tcx.inhabitedness_cache.borrow();
+                    if let Some(forest) = cache.get(&global_ty) {
+                        return forest.clone();
+                    }
+                }
+                let forest = global_ty.uninhabited_from_inner(visited, tcx);
+                let mut cache = tcx.inhabitedness_cache.borrow_mut();
+                cache.insert(global_ty, forest.clone());
+                forest
+            },
+            None => {
+                let forest = self.uninhabited_from_inner(visited, tcx);
+                forest
+            },
+        }
+    }
+
+    fn uninhabited_from_inner(
+                &self,
+                visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
+    {
+        match self.sty {
+            TyAdt(def, substs) => {
+                def.uninhabited_from(visited, tcx, substs)
+            },
+
+            TyNever => DefIdForest::full(tcx),
+            TyTuple(ref tys) => {
+                DefIdForest::union(tcx, tys.iter().map(|ty| {
+                    ty.uninhabited_from(visited, tcx)
+                }))
+            },
+            TyArray(ty, len) => {
+                if len == 0 {
+                    DefIdForest::empty()
+                } else {
+                    ty.uninhabited_from(visited, tcx)
+                }
+            }
+            TyRef(_, ref tm) => tm.ty.uninhabited_from(visited, tcx),
+
+            _ => DefIdForest::empty(),
+        }
+    }
+}
+
index 3e33d246b6d183046017d0ce6b0a59420fe6ea98..fa62e893a2875215047b061d4b6324869ac80dca 100644 (file)
@@ -29,7 +29,7 @@
 use ty::subst::{Subst, Substs};
 use ty::walk::TypeWalker;
 use util::common::MemoizationMap;
-use util::nodemap::{NodeSet, NodeMap, FxHashMap, FxHashSet};
+use util::nodemap::{NodeSet, NodeMap, FxHashMap};
 
 use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
@@ -78,6 +78,7 @@
 pub mod error;
 pub mod fast_reject;
 pub mod fold;
+pub mod inhabitedness;
 pub mod item_path;
 pub mod layout;
 pub mod _match;
@@ -226,6 +227,20 @@ pub enum Visibility {
 
 pub trait DefIdTree: Copy {
     fn parent(self, id: DefId) -> Option<DefId>;
+
+    fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
+        if descendant.krate != ancestor.krate {
+            return false;
+        }
+
+        while descendant != ancestor {
+            match self.parent(descendant) {
+                Some(parent) => descendant = parent,
+                None => return false,
+            }
+        }
+        true
+    }
 }
 
 impl<'a, 'gcx, 'tcx> DefIdTree for TyCtxt<'a, 'gcx, 'tcx> {
@@ -252,7 +267,7 @@ pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: TyCtxt) -> Self {
     }
 
     /// Returns true if an item with this visibility is accessible from the given block.
-    pub fn is_accessible_from<T: DefIdTree>(self, mut module: DefId, tree: T) -> bool {
+    pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
         let restriction = match self {
             // Public items are visible everywhere.
             Visibility::Public => return true,
@@ -263,14 +278,7 @@ pub fn is_accessible_from<T: DefIdTree>(self, mut module: DefId, tree: T) -> boo
             Visibility::Restricted(module) => module,
         };
 
-        while module != restriction {
-            match tree.parent(module) {
-                Some(parent) => module = parent,
-                None => return false,
-            }
-        }
-
-        true
+        tree.is_descendant_of(module, restriction)
     }
 
     /// Returns true if this visibility is at least as accessible as the given visibility
@@ -1406,20 +1414,6 @@ fn calculate_dtorck(&'gcx self, tcx: TyCtxt) {
         self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID)
     }
 
-    #[inline]
-    pub fn is_uninhabited_recurse(&self,
-                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
-                                  block: Option<NodeId>,
-                                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                  substs: &'tcx Substs<'tcx>) -> bool {
-        if !visited.insert((self.did, substs)) {
-            return false;
-        };
-        self.variants.iter().all(|v| {
-            v.is_uninhabited_recurse(visited, block, tcx, substs, self.is_union())
-        })
-    }
-
     #[inline]
     pub fn is_struct(&self) -> bool {
         !self.is_union() && !self.is_enum()
@@ -1754,36 +1748,12 @@ pub fn index_of_field_named(&self,
     pub fn field_named(&self, name: ast::Name) -> &FieldDef {
         self.find_field_named(name).unwrap()
     }
-
-    #[inline]
-    pub fn is_uninhabited_recurse(&self,
-                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
-                                  block: Option<NodeId>,
-                                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                  substs: &'tcx Substs<'tcx>,
-                                  is_union: bool) -> bool {
-        if is_union {
-            self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, block, tcx, substs))
-        } else {
-            self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, block, tcx, substs))
-        }
-    }
 }
 
 impl<'a, 'gcx, 'tcx> FieldDef {
     pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> {
         tcx.item_type(self.did).subst(tcx, subst)
     }
-
-    #[inline]
-    pub fn is_uninhabited_recurse(&self,
-                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
-                                  block: Option<NodeId>,
-                                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                  substs: &'tcx Substs<'tcx>) -> bool {
-        block.map_or(true, |b| tcx.vis_is_accessible_from(self.vis, b)) &&
-        self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
-    }
 }
 
 /// Records the substitutions used to translate the polytype for an
index 638345608c2f5d9743595101ff8352a506d07d4d..81b0a55841ad839e58547a58565e207dca8af488 100644 (file)
@@ -22,7 +22,7 @@
 use std::iter;
 use std::cmp::Ordering;
 use syntax::abi;
-use syntax::ast::{self, Name, NodeId};
+use syntax::ast::{self, Name};
 use syntax::symbol::{keywords, InternedString};
 use util::nodemap::FxHashSet;
 
@@ -979,29 +979,52 @@ pub fn is_never(&self) -> bool {
         }
     }
 
-    /// Checks whether a type is uninhabited.
-    /// If `block` is `Some(id)` it also checks that the uninhabited-ness is visible from `id`.
-    pub fn is_uninhabited(&self, block: Option<NodeId>, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+    /// Checks whether a type is visibly uninhabited from a particular module.
+    /// # Example
+    /// ```rust
+    /// enum Void {}
+    /// mod a {
+    ///     pub mod b {
+    ///         pub struct SecretlyUninhabited {
+    ///             _priv: !,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// mod c {
+    ///     pub struct AlsoSecretlyUninhabited {
+    ///         _priv: Void,
+    ///     }
+    ///     mod d {
+    ///     }
+    /// }
+    ///
+    /// struct Foo {
+    ///     x: a::b::SecretlyUninhabited,
+    ///     y: c::AlsoSecretlyUninhabited,
+    /// }
+    /// ```
+    /// In this code, the type `Foo` will only be visibly uninhabited inside the
+    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
+    /// contain `Foo`.
+    ///
+    /// # Example
+    /// ```rust
+    /// let foo_result: Result<T, Foo> = ... ;
+    /// let Ok(t) = foo_result;
+    /// ```
+    /// This code should only compile in modules where the uninhabitedness of Foo is
+    /// visible.
+    pub fn is_uninhabited_from(&self, module: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
         let mut visited = FxHashSet::default();
-        self.is_uninhabited_recurse(&mut visited, block, cx)
-    }
-
-    pub fn is_uninhabited_recurse(&self,
-                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
-                                  block: Option<NodeId>,
-                                  cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
-        match self.sty {
-            TyAdt(def, substs) => {
-                def.is_uninhabited_recurse(visited, block, cx, substs)
-            },
-
-            TyNever => true,
-            TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, block, cx)),
-            TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, block, cx),
-            TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, block, cx),
-
-            _ => false,
-        }
+        let forest = self.uninhabited_from(&mut visited, tcx);
+
+        // To check whether this type is uninhabited at all (not just from the
+        // given node) you could check whether the forest is empty.
+        // ```
+        // forest.is_empty()
+        // ```
+        forest.contains(tcx, module)
     }
 
     pub fn is_primitive(&self) -> bool {
index 0b45ff94a93123bffad6a5c2f6ba43626a3bd439..0b1030f74b0fdba305322b5eb87e57fd4e7cf1af 100644 (file)
@@ -15,7 +15,7 @@
 use infer::InferCtxt;
 use hir::map as ast_map;
 use traits::{self, Reveal};
-use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::{Disr, ParameterEnvironment};
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
@@ -120,9 +120,8 @@ fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
 
 
 #[derive(Copy, Clone)]
-pub enum CopyImplementationError {
-    InfrigingField(Name),
-    InfrigingVariant(Name),
+pub enum CopyImplementationError<'tcx> {
+    InfrigingField(&'tcx ty::FieldDef),
     NotAnAdt,
     HasDestructor
 }
@@ -145,37 +144,30 @@ pub enum Representability {
 impl<'tcx> ParameterEnvironment<'tcx> {
     pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        self_type: Ty<'tcx>, span: Span)
-                                       -> Result<(),CopyImplementationError> {
+                                       -> Result<(), CopyImplementationError> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| {
-            let adt = match self_type.sty {
-                ty::TyAdt(adt, substs) => match adt.adt_kind() {
-                    AdtKind::Struct | AdtKind::Union => {
-                        for field in adt.all_fields() {
-                            let field_ty = field.ty(tcx, substs);
-                            if infcx.type_moves_by_default(field_ty, span) {
-                                return Err(CopyImplementationError::InfrigingField(
-                                    field.name))
-                            }
-                        }
-                        adt
-                    }
-                    AdtKind::Enum => {
-                        for variant in &adt.variants {
-                            for field in &variant.fields {
-                                let field_ty = field.ty(tcx, substs);
-                                if infcx.type_moves_by_default(field_ty, span) {
-                                    return Err(CopyImplementationError::InfrigingVariant(
-                                        variant.name))
-                                }
-                            }
-                        }
-                        adt
-                    }
-                },
+        tcx.infer_ctxt(None, Some(self.clone()), Reveal::NotSpecializable).enter(|infcx| {
+            let (adt, substs) = match self_type.sty {
+                ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt)
             };
 
+            let field_implements_copy = |field: &ty::FieldDef| {
+                let cause = traits::ObligationCause::dummy();
+                match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) {
+                    Ok(ty) => !infcx.type_moves_by_default(ty, span),
+                    Err(..) => false
+                }
+            };
+
+            for variant in &adt.variants {
+                for field in &variant.fields {
+                    if !field_implements_copy(field) {
+                        return Err(CopyImplementationError::InfrigingField(field));
+                    }
+                }
+            }
+
             if adt.has_dtor() {
                 return Err(CopyImplementationError::HasDestructor);
             }
index 1dffff598096b9c8e4b310cff69f452a7a9665e5..c5e1e107753ffa80c56b543d5e04e29daa5c689b 100644 (file)
@@ -25,14 +25,7 @@ pub fn opts() -> TargetOptions {
             "-Wl,--as-needed".to_string(),
 
             // Always enable NX protection when it is available
-            "-Wl,-z,noexecstack".to_string(),
-
-            // Static link
-            "-static".to_string()
-        ],
-        late_link_args: vec![
-            "-lc".to_string(),
-            "-lm".to_string()
+            "-Wl,-z,noexecstack".to_string()
         ],
         executables: true,
         relocation_model: "static".to_string(),
@@ -40,7 +33,6 @@ pub fn opts() -> TargetOptions {
         eliminate_frame_pointer: false,
         target_family: None,
         linker_is_gnu: true,
-        no_default_libraries: true,
         lib_allocation_crate: "alloc_system".to_string(),
         exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
index ebe103490110436e6712fbf3b86b52805cf655c8..f4b3646fce02c02840c0bc1061961273b0c67653 100644 (file)
 
 use rustc_const_math::ConstInt;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::Idx;
 
 use pattern::{FieldPattern, Pattern, PatternKind};
 use pattern::{PatternFoldable, PatternFolder};
 
-use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
 
-use rustc::hir;
-use rustc::hir::def::CtorKind;
-use rustc::hir::{Pat, PatKind};
+use rustc::mir::Field;
 use rustc::util::common::ErrorReported;
 
-use syntax::ast::{self, DUMMY_NODE_ID};
-use syntax::codemap::Spanned;
-use syntax::ptr::P;
 use syntax_pos::{Span, DUMMY_SP};
 
 use arena::TypedArena;
@@ -74,12 +68,6 @@ fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
     }
 }
 
-pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
-    id: DUMMY_NODE_ID,
-    node: PatKind::Wild,
-    span: DUMMY_SP
-};
-
 impl<'tcx> Pattern<'tcx> {
     fn is_wildcard(&self) -> bool {
         match *self.kind {
@@ -156,9 +144,13 @@ fn from_iter<T: IntoIterator<Item=Vec<&'a Pattern<'tcx>>>>(iter: T) -> Self
 //NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
 pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    /// A wild pattern with an error type - it exists to avoid having to normalize
-    /// associated types to get field types.
-    pub wild_pattern: &'a Pattern<'tcx>,
+    /// The module in which the match occurs. This is necessary for
+    /// checking inhabited-ness of types because whether a type is (visibly)
+    /// inhabited can depend on whether it was defined in the current module or
+    /// not. eg. `struct Foo { _private: ! }` cannot be seen to be empty
+    /// outside it's module and should not be matchable with an empty match
+    /// statement.
+    pub module: DefId,
     pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
     pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>,
 }
@@ -166,27 +158,24 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
 impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
     pub fn create_and_enter<F, R>(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        module: DefId,
         f: F) -> R
         where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
     {
-        let wild_pattern = Pattern {
-            ty: tcx.types.err,
-            span: DUMMY_SP,
-            kind: box PatternKind::Wild
-        };
-
         let pattern_arena = TypedArena::new();
 
         f(MatchCheckCtxt {
             tcx: tcx,
-            wild_pattern: &wild_pattern,
+            module: module,
             pattern_arena: &pattern_arena,
             byte_array_map: FxHashMap(),
         })
     }
 
     // convert a byte-string pattern to a list of u8 patterns.
-    fn lower_byte_str_pattern(&mut self, pat: &'a Pattern<'tcx>) -> Vec<&'a Pattern<'tcx>> {
+    fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
+            where 'a: 'p
+    {
         let pattern_arena = &*self.pattern_arena;
         let tcx = self.tcx;
         self.byte_array_map.entry(pat).or_insert_with(|| {
@@ -224,25 +213,34 @@ pub enum Constructor {
 }
 
 impl<'tcx> Constructor {
-    fn variant_for_adt(&self, adt: &'tcx ty::AdtDef) -> &'tcx ty::VariantDef {
+    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
         match self {
-            &Variant(vid) => adt.variant_with_id(vid),
+            &Variant(vid) => adt.variant_index_with_id(vid),
             &Single => {
                 assert_eq!(adt.variants.len(), 1);
-                &adt.variants[0]
+                0
             }
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
         }
     }
 }
 
-#[derive(Clone, PartialEq)]
-pub enum Usefulness {
+#[derive(Clone)]
+pub enum Usefulness<'tcx> {
     Useful,
-    UsefulWithWitness(Vec<Witness>),
+    UsefulWithWitness(Vec<Witness<'tcx>>),
     NotUseful
 }
 
+impl<'tcx> Usefulness<'tcx> {
+    fn is_useful(&self) -> bool {
+        match *self {
+            NotUseful => false,
+            _ => true
+        }
+    }
+}
+
 #[derive(Copy, Clone)]
 pub enum WitnessPreference {
     ConstructWitness,
@@ -255,39 +253,31 @@ struct PatternContext<'tcx> {
     max_slice_length: usize,
 }
 
-
-fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
-    let node = match value {
-        &ConstVal::Bool(b) => ast::LitKind::Bool(b),
-        _ => bug!()
-    };
-    P(hir::Expr {
-        id: DUMMY_NODE_ID,
-        node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
-        span: DUMMY_SP,
-        attrs: ast::ThinVec::new(),
-    })
-}
-
 /// A stack of patterns in reverse order of construction
-#[derive(Clone, PartialEq, Eq)]
-pub struct Witness(Vec<P<Pat>>);
+#[derive(Clone)]
+pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
 
-impl Witness {
-    pub fn single_pattern(&self) -> &Pat {
+impl<'tcx> Witness<'tcx> {
+    pub fn single_pattern(&self) -> &Pattern<'tcx> {
         assert_eq!(self.0.len(), 1);
         &self.0[0]
     }
 
-    fn push_wild_constructor<'a, 'tcx>(
+    fn push_wild_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
         ctor: &Constructor,
         ty: Ty<'tcx>)
         -> Self
     {
-        let arity = constructor_arity(cx, ctor, ty);
-        self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone())));
+        let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty);
+        self.0.extend(sub_pattern_tys.into_iter().map(|ty| {
+            Pattern {
+                ty: ty,
+                span: DUMMY_SP,
+                kind: box PatternKind::Wild,
+            }
+        }));
         self.apply_constructor(cx, ctor, ty)
     }
 
@@ -305,7 +295,7 @@ fn push_wild_constructor<'a, 'tcx>(
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'a, 'tcx>(
+    fn apply_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a,'tcx>,
         ctor: &Constructor,
@@ -318,110 +308,121 @@ fn apply_constructor<'a, 'tcx>(
             let mut pats = self.0.drain(len-arity..).rev();
 
             match ty.sty {
-                ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
-
-                ty::TyAdt(adt, _) => {
-                    let v = ctor.variant_for_adt(adt);
-                    let qpath = hir::QPath::Resolved(None, P(hir::Path {
-                        span: DUMMY_SP,
-                        def: Def::Err,
-                        segments: vec![hir::PathSegment::from_name(v.name)].into(),
-                    }));
-                    match v.ctor_kind {
-                        CtorKind::Fictive => {
-                            let field_pats: hir::HirVec<_> = v.fields.iter()
-                                .zip(pats)
-                                .filter(|&(_, ref pat)| pat.node != PatKind::Wild)
-                                .map(|(field, pat)| Spanned {
-                                    span: DUMMY_SP,
-                                    node: hir::FieldPat {
-                                        name: field.name,
-                                        pat: pat,
-                                        is_shorthand: false,
-                                    }
-                                }).collect();
-                            let has_more_fields = field_pats.len() < arity;
-                            PatKind::Struct(qpath, field_pats, has_more_fields)
+                ty::TyAdt(..) |
+                ty::TyTuple(..) => {
+                    let pats = pats.enumerate().map(|(i, p)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: p
                         }
-                        CtorKind::Fn => {
-                            PatKind::TupleStruct(qpath, pats.collect(), None)
+                    }).collect();
+
+                    if let ty::TyAdt(adt, substs) = ty.sty {
+                        if adt.variants.len() > 1 {
+                            PatternKind::Variant {
+                                adt_def: adt,
+                                substs: substs,
+                                variant_index: ctor.variant_index_for_adt(adt),
+                                subpatterns: pats
+                            }
+                        } else {
+                            PatternKind::Leaf { subpatterns: pats }
                         }
-                        CtorKind::Const => PatKind::Path(qpath)
+                    } else {
+                        PatternKind::Leaf { subpatterns: pats }
                     }
                 }
 
-                ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
-                    PatKind::Ref(pats.nth(0).unwrap(), mutbl)
+                ty::TyRef(..) => {
+                    PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
                 }
 
                 ty::TySlice(_) | ty::TyArray(..) => {
-                    PatKind::Slice(pats.collect(), None, hir::HirVec::new())
+                    PatternKind::Slice {
+                        prefix: pats.collect(),
+                        slice: None,
+                        suffix: vec![]
+                    }
                 }
 
                 _ => {
                     match *ctor {
-                        ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)),
-                        _ => PatKind::Wild,
+                        ConstantValue(ref v) => PatternKind::Constant { value: v.clone() },
+                        _ => PatternKind::Wild,
                     }
                 }
             }
         };
 
-        self.0.push(P(hir::Pat {
-            id: DUMMY_NODE_ID,
-            node: pat,
-            span: DUMMY_SP
-        }));
+        self.0.push(Pattern {
+            ty: ty,
+            span: DUMMY_SP,
+            kind: Box::new(pat),
+        });
 
         self
     }
 }
 
-/// Return the set of constructors from the same type as the first column of `matrix`,
-/// that are matched only by wildcard patterns from that first column.
-///
-/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
-/// still be unmatched if the first constructor is replaced by any of the constructors
-/// in the return value.
-fn missing_constructors(cx: &mut MatchCheckCtxt,
-                        matrix: &Matrix,
-                        pcx: PatternContext) -> Vec<Constructor> {
-    let used_constructors: Vec<Constructor> =
-        matrix.0.iter()
-        .flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
-        .collect();
-    debug!("used_constructors = {:?}", used_constructors);
-    all_constructors(cx, pcx).into_iter()
-        .filter(|c| !used_constructors.contains(c))
-        .collect()
-}
-
 /// This determines the set of all possible constructors of a pattern matching
 /// values of type `left_ty`. For vectors, this would normally be an infinite set
+/// but is instead bounded by the maximum fixed length of slice patterns in
+/// the column of patterns being analyzed.
 ///
 /// This intentionally does not list ConstantValue specializations for
 /// non-booleans, because we currently assume that there is always a
 /// "non-standard constant" that matches. See issue #12483.
 ///
-/// but is instead bounded by the maximum fixed length of slice patterns in
-/// the column of patterns being analyzed.
-fn all_constructors(_cx: &mut MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructor> {
+/// We make sure to omit constructors that are statically impossible. eg for
+/// Option<!> we do not include Some(_) in the returned list of constructors.
+fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                                  pcx: PatternContext<'tcx>) -> Vec<Constructor>
+{
+    debug!("all_constructors({:?})", pcx.ty);
     match pcx.ty.sty {
         ty::TyBool =>
             [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
-        ty::TySlice(_) =>
-            (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(),
-        ty::TyArray(_, length) => vec![Slice(length)],
-        ty::TyAdt(def, _) if def.is_enum() && def.variants.len() > 1 =>
-            def.variants.iter().map(|v| Variant(v.did)).collect(),
-        _ => vec![Single]
+        ty::TySlice(ref sub_ty) => {
+            if sub_ty.is_uninhabited_from(cx.module, cx.tcx) {
+                vec![Slice(0)]
+            } else {
+                (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
+            }
+        }
+        ty::TyArray(ref sub_ty, length) => {
+            if length == 0 || !sub_ty.is_uninhabited_from(cx.module, cx.tcx) {
+                vec![Slice(length)]
+            } else {
+                vec![]
+            }
+        }
+        ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
+            def.variants.iter().filter_map(|v| {
+                let mut visited = FxHashSet::default();
+                let forest = v.uninhabited_from(&mut visited,
+                                                cx.tcx, substs,
+                                                AdtKind::Enum);
+                if forest.contains(cx.tcx, cx.module) {
+                    None
+                } else {
+                    Some(Variant(v.did))
+                }
+            }).collect()
+        }
+        _ => {
+            if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) {
+                vec![]
+            } else {
+                vec![Single]
+            }
+        }
     }
 }
 
-fn max_slice_length<'a, 'tcx, I>(
+fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     _cx: &mut MatchCheckCtxt<'a, 'tcx>,
     patterns: I) -> usize
-    where I: Iterator<Item=&'a Pattern<'tcx>>
+    where I: Iterator<Item=&'p Pattern<'tcx>>
 {
     // The exhaustiveness-checking paper does not include any details on
     // checking variable-length slice patterns. However, they are matched
@@ -512,6 +513,12 @@ fn max_slice_length<'a, 'tcx, I>(
 }
 
 /// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
+/// The algorithm from the paper has been modified to correctly handle empty
+/// types. The changes are:
+///   (0) We don't exit early if the pattern matrix has zero rows. We just
+///       continue to recurse over columns.
+///   (1) all_constructors will only return constructors that are statically
+///       possible. eg. it will only return Ok for Result<T, !>
 ///
 /// Whether a vector `v` of patterns is 'useful' in relation to a set of such
 /// vectors `m` is defined as there being a set of inputs that will match `v`
@@ -521,29 +528,30 @@ fn max_slice_length<'a, 'tcx, I>(
 /// relation to preceding patterns, it is not reachable) and exhaustiveness
 /// checking (if a wildcard pattern is useful in relation to a matrix, the
 /// matrix isn't exhaustive).
-///
-/// Note: is_useful doesn't work on empty types, as the paper notes.
-/// So it assumes that v is non-empty.
-pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                           matrix: &Matrix<'a, 'tcx>,
-                           v: &[&'a Pattern<'tcx>],
+pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                           matrix: &Matrix<'p, 'tcx>,
+                           v: &[&'p Pattern<'tcx>],
                            witness: WitnessPreference)
-                           -> Usefulness {
+                           -> Usefulness<'tcx> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:?}, {:?})", matrix, v);
-    if rows.is_empty() {
-        return match witness {
-            ConstructWitness => UsefulWithWitness(vec![Witness(
-                repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect()
-            )]),
-            LeaveOutWitness => Useful
-        };
-    }
-    if rows[0].is_empty() {
-        return NotUseful;
-    }
 
-    let &Matrix(ref rows) = matrix;
+    // The base case. We are pattern-matching on () and the return value is
+    // based on whether our matrix has a row or not.
+    // NOTE: This could potentially be optimized by checking rows.is_empty()
+    // first and then, if v is non-empty, the return value is based on whether
+    // the type of the tuple we're checking is inhabited or not.
+    if v.is_empty() {
+        return if rows.is_empty() {
+            match witness {
+                ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
+                LeaveOutWitness => Useful,
+            }
+        } else {
+            NotUseful
+        }
+    };
+
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
 
@@ -559,15 +567,33 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         debug!("is_useful - expanding constructors: {:?}", constructors);
         constructors.into_iter().map(|c|
             is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
-        ).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+        ).find(|result| result.is_useful()).unwrap_or(NotUseful)
     } else {
         debug!("is_useful - expanding wildcard");
-        let constructors = missing_constructors(cx, matrix, pcx);
-        debug!("is_useful - missing_constructors = {:?}", constructors);
-        if constructors.is_empty() {
-            all_constructors(cx, pcx).into_iter().map(|c| {
+
+        let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
+            pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
+        }).collect();
+        debug!("used_ctors = {:?}", used_ctors);
+        let all_ctors = all_constructors(cx, pcx);
+        debug!("all_ctors = {:?}", all_ctors);
+        let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
+            !used_ctors.contains(*c)
+        }).cloned().collect();
+        debug!("missing_ctors = {:?}", missing_ctors);
+
+        // `missing_ctors` is the set of constructors from the same type as the
+        // first column of `matrix` that are matched only by wildcard patterns
+        // from the first column.
+        //
+        // Therefore, if there is some pattern that is unmatched by `matrix`,
+        // it will still be unmatched if the first constructor is replaced by
+        // any of the constructors in `missing_ctors`
+
+        if missing_ctors.is_empty() {
+            all_ctors.into_iter().map(|c| {
                 is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
-            }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+            }).find(|result| result.is_useful()).unwrap_or(NotUseful)
         } else {
             let matrix = rows.iter().filter_map(|r| {
                 if r[0].is_wildcard() {
@@ -579,11 +605,25 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             match is_useful(cx, &matrix, &v[1..], witness) {
                 UsefulWithWitness(pats) => {
                     let cx = &*cx;
-                    UsefulWithWitness(pats.into_iter().flat_map(|witness| {
-                        constructors.iter().map(move |ctor| {
-                            witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
-                        })
-                    }).collect())
+                    let new_witnesses = if used_ctors.is_empty() {
+                        // All constructors are unused. Add wild patterns
+                        // rather than each individual constructor
+                        pats.into_iter().map(|mut witness| {
+                            witness.0.push(Pattern {
+                                ty: pcx.ty,
+                                span: DUMMY_SP,
+                                kind: box PatternKind::Wild,
+                            });
+                            witness
+                        }).collect()
+                    } else {
+                        pats.into_iter().flat_map(|witness| {
+                            missing_ctors.iter().map(move |ctor| {
+                                witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
+                            })
+                        }).collect()
+                    };
+                    UsefulWithWitness(new_witnesses)
                 }
                 result => result
             }
@@ -591,19 +631,27 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-fn is_useful_specialized<'a, 'tcx>(
+fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    &Matrix(ref m): &Matrix<'a, 'tcx>,
-    v: &[&'a Pattern<'tcx>],
+    &Matrix(ref m): &Matrix<'p, 'tcx>,
+    v: &[&'p Pattern<'tcx>],
     ctor: Constructor,
     lty: Ty<'tcx>,
-    witness: WitnessPreference) -> Usefulness
+    witness: WitnessPreference) -> Usefulness<'tcx>
 {
-    let arity = constructor_arity(cx, &ctor, lty);
+    let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
+    let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
+        Pattern {
+            ty: ty,
+            span: DUMMY_SP,
+            kind: box PatternKind::Wild,
+        }
+    }).collect();
+    let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
     let matrix = Matrix(m.iter().flat_map(|r| {
-        specialize(cx, &r[..], &ctor, 0, arity)
+        specialize(cx, &r[..], &ctor, &wild_patterns)
     }).collect());
-    match specialize(cx, v, &ctor, 0, arity) {
+    match specialize(cx, v, &ctor, &wild_patterns) {
         Some(v) => match is_useful(cx, &matrix, &v[..], witness) {
             UsefulWithWitness(witnesses) => UsefulWithWitness(
                 witnesses.into_iter()
@@ -672,12 +720,39 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
         },
         ty::TyRef(..) => 1,
         ty::TyAdt(adt, _) => {
-            ctor.variant_for_adt(adt).fields.len()
+            adt.variants[ctor.variant_index_for_adt(adt)].fields.len()
         }
         _ => 0
     }
 }
 
+/// This computes the types of the sub patterns that a constructor should be
+/// expanded to.
+///
+/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
+fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
+                                             ctor: &Constructor,
+                                             ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
+{
+    debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
+    match ty.sty {
+        ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(),
+        ty::TyBox(ty) => vec![ty],
+        ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
+            Slice(length) => repeat(ty).take(length).collect(),
+            ConstantValue(_) => vec![],
+            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
+        },
+        ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
+        ty::TyAdt(adt, substs) => {
+            adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
+                field.ty(cx.tcx, substs)
+            }).collect()
+        }
+        _ => vec![],
+    }
+}
+
 fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
                                     ctor: &Constructor,
                                     prefix: &[Pattern],
@@ -729,19 +804,18 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
     Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
 }
 
-fn patterns_for_variant<'a, 'tcx>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    subpatterns: &'a [FieldPattern<'tcx>],
-    arity: usize)
-    -> Vec<&'a Pattern<'tcx>>
+fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
+    subpatterns: &'p [FieldPattern<'tcx>],
+    wild_patterns: &[&'p Pattern<'tcx>])
+    -> Vec<&'p Pattern<'tcx>>
 {
-    let mut result = vec![cx.wild_pattern; arity];
+    let mut result = wild_patterns.to_owned();
 
     for subpat in subpatterns {
         result[subpat.field.index()] = &subpat.pattern;
     }
 
-    debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, arity, result);
+    debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
     result
 }
 
@@ -753,35 +827,41 @@ fn patterns_for_variant<'a, 'tcx>(
 /// different patterns.
 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 /// fields filled with wild patterns.
-fn specialize<'a, 'tcx>(
+fn specialize<'p, 'a: 'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    r: &[&'a Pattern<'tcx>],
-    constructor: &Constructor, col: usize, arity: usize)
-    -> Option<Vec<&'a Pattern<'tcx>>>
+    r: &[&'p Pattern<'tcx>],
+    constructor: &Constructor,
+    wild_patterns: &[&'p Pattern<'tcx>])
+    -> Option<Vec<&'p Pattern<'tcx>>>
 {
-    let pat = &r[col];
+    let pat = &r[0];
 
     let head: Option<Vec<&Pattern>> = match *pat.kind {
-        PatternKind::Binding { .. } | PatternKind::Wild =>
-            Some(vec![cx.wild_pattern; arity]),
+        PatternKind::Binding { .. } | PatternKind::Wild => {
+            Some(wild_patterns.to_owned())
+        },
 
-        PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
+        PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let ref variant = adt_def.variants[variant_index];
             if *constructor == Variant(variant.did) {
-                Some(patterns_for_variant(cx, subpatterns, arity))
+                Some(patterns_for_variant(subpatterns, wild_patterns))
             } else {
                 None
             }
         }
 
-        PatternKind::Leaf { ref subpatterns } => Some(patterns_for_variant(cx, subpatterns, arity)),
-        PatternKind::Deref { ref subpattern } => Some(vec![subpattern]),
+        PatternKind::Leaf { ref subpatterns } => {
+            Some(patterns_for_variant(subpatterns, wild_patterns))
+        }
+        PatternKind::Deref { ref subpattern } => {
+            Some(vec![subpattern])
+        }
 
         PatternKind::Constant { ref value } => {
             match *constructor {
                 Slice(..) => match *value {
                     ConstVal::ByteStr(ref data) => {
-                        if arity == data.len() {
+                        if wild_patterns.len() == data.len() {
                             Some(cx.lower_byte_str_pattern(pat))
                         } else {
                             None
@@ -817,11 +897,14 @@ fn specialize<'a, 'tcx>(
             match *constructor {
                 Slice(..) => {
                     let pat_len = prefix.len() + suffix.len();
-                    if let Some(slice_count) = arity.checked_sub(pat_len) {
+                    if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) {
                         if slice_count == 0 || slice.is_some() {
                             Some(
                                 prefix.iter().chain(
-                                repeat(cx.wild_pattern).take(slice_count).chain(
+                                wild_patterns.iter().map(|p| *p)
+                                                    .skip(prefix.len())
+                                                    .take(slice_count)
+                                                    .chain(
                                 suffix.iter()
                             )).collect())
                         } else {
@@ -845,11 +928,10 @@ fn specialize<'a, 'tcx>(
             }
         }
     };
-    debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head);
+    debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head);
 
     head.map(|mut head| {
-        head.extend_from_slice(&r[..col]);
-        head.extend_from_slice(&r[col + 1..]);
+        head.extend_from_slice(&r[1 ..]);
         head
     })
 }
index 01b19e1f53979d8dd563a9ed60873b47983fe98b..2949cf0d535bfd286bca8e4554dc7f243d7417cc 100644 (file)
@@ -9,11 +9,10 @@
 // except according to those terms.
 
 use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
-use _match::{DUMMY_WILD_PAT};
 use _match::Usefulness::*;
 use _match::WitnessPreference::*;
 
-use pattern::{Pattern, PatternContext, PatternError};
+use pattern::{Pattern, PatternContext, PatternError, PatternKind};
 
 use eval::report_const_eval_err;
 
@@ -25,8 +24,9 @@
 use rustc::middle::mem_categorization::{cmt};
 use rustc::session::Session;
 use rustc::traits::Reveal;
-use rustc::ty::{self, TyCtxt};
-use rustc_errors::DiagnosticBuilder;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::lint;
+use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
 
 use rustc::hir::def::*;
 use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
@@ -36,7 +36,7 @@
 
 use syntax::ast;
 use syntax::ptr::P;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
@@ -81,7 +81,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
 
         match ex.node {
             hir::ExprMatch(ref scrut, ref arms, source) => {
-                self.check_match(scrut, arms, source, ex.span);
+                self.check_match(scrut, arms, source);
             }
             _ => {}
         }
@@ -117,13 +117,6 @@ fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
     fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
         for error in patcx.errors {
             match error {
-                PatternError::BadConstInPattern(span, def_id) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        &format!("constants of the type `{}` \
-                                  cannot be used in patterns",
-                                 self.tcx.item_path_str(def_id)));
-                }
                 PatternError::StaticInPattern(span) => {
                     span_err!(self.tcx.sess, span, E0158,
                               "statics cannot be referenced in patterns");
@@ -139,8 +132,7 @@ fn check_match(
         &self,
         scrut: &hir::Expr,
         arms: &[hir::Arm],
-        source: hir::MatchSource,
-        span: Span)
+        source: hir::MatchSource)
     {
         for arm in arms {
             // First, check legality of move bindings.
@@ -158,7 +150,8 @@ fn check_match(
             }
         }
 
-        MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| {
+        let module = self.tcx.map.local_def_id(self.tcx.map.get_module_parent(scrut.id));
+        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut have_errors = false;
 
             let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
@@ -182,32 +175,14 @@ fn check_match(
             // Fourth, check for unreachable arms.
             check_arms(cx, &inlined_arms, source);
 
-            // Finally, check if the whole match expression is exhaustive.
-            // Check for empty enum, because is_useful only works on inhabited types.
-            let pat_ty = self.tcx.tables().node_id_to_type(scrut.id);
-            if inlined_arms.is_empty() {
-                if !pat_ty.is_uninhabited(Some(scrut.id), self.tcx) {
-                    // We know the type is inhabited, so this must be wrong
-                    let mut err = create_e0004(self.tcx.sess, span,
-                                               format!("non-exhaustive patterns: type {} \
-                                                        is non-empty",
-                                                       pat_ty));
-                    span_help!(&mut err, span,
-                               "Please ensure that all possible cases are being handled; \
-                                possibly adding wildcards or more match arms.");
-                    err.emit();
-                }
-                // If the type *is* uninhabited, it's vacuously exhaustive
-                return;
-            }
-
             let matrix: Matrix = inlined_arms
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
                 .flat_map(|arm| &arm.0)
                 .map(|pat| vec![pat.0])
                 .collect();
-            check_exhaustive(cx, scrut.span, &matrix, source);
+            let scrut_ty = cx.tcx.tables().node_id_to_type(scrut.id);
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, source);
         })
     }
 
@@ -218,21 +193,27 @@ fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
             "local binding"
         };
 
-        MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| {
+        let module = self.tcx.map.local_def_id(self.tcx.map.get_module_parent(pat.id));
+        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut patcx = PatternContext::new(self.tcx);
+            let pattern = patcx.lower_pattern(pat);
+            let pattern_ty = pattern.ty;
             let pats : Matrix = vec![vec![
-                expand_pattern(cx, patcx.lower_pattern(pat))
+                expand_pattern(cx, pattern)
             ]].into_iter().collect();
 
-            let witness = match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
+            let wild_pattern = Pattern {
+                ty: pattern_ty,
+                span: DUMMY_SP,
+                kind: box PatternKind::Wild,
+            };
+            let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
                 UsefulWithWitness(witness) => witness,
                 NotUseful => return,
                 Useful => bug!()
             };
 
-            let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
-                s.print_pat(witness[0].single_pattern())
-            });
+            let pattern_string = witness[0].single_pattern().to_string();
             let mut diag = struct_span_err!(
                 self.tcx.sess, pat.span, E0005,
                 "refutable pattern in {}: `{}` not covered",
@@ -334,14 +315,16 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                         },
 
                         hir::MatchSource::Normal => {
-                            let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
-                                                           "unreachable pattern");
-                            err.span_label(pat.span, &"this is an unreachable pattern");
+                            let mut diagnostic = Diagnostic::new(Level::Warning,
+                                                                 "unreachable pattern");
+                            diagnostic.set_span(pat.span);
                             // if we had a catchall pattern, hint at that
                             if let Some(catchall) = catchall {
-                                err.span_note(catchall, "this pattern matches any value");
+                                diagnostic.span_label(pat.span, &"this is an unreachable pattern");
+                                diagnostic.span_note(catchall, "this pattern matches any value");
                             }
-                            err.emit();
+                            cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
+                                                            hir_pat.id, diagnostic);
                         },
 
                         hir::MatchSource::TryDesugar => {
@@ -363,29 +346,33 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 }
 
 fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                              scrut_ty: Ty<'tcx>,
                               sp: Span,
                               matrix: &Matrix<'a, 'tcx>,
                               source: hir::MatchSource) {
-    match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
+    let wild_pattern = Pattern {
+        ty: scrut_ty,
+        span: DUMMY_SP,
+        kind: box PatternKind::Wild,
+    };
+    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
         UsefulWithWitness(pats) => {
             let witnesses = if pats.is_empty() {
-                vec![DUMMY_WILD_PAT]
+                vec![&wild_pattern]
             } else {
                 pats.iter().map(|w| w.single_pattern()).collect()
             };
             match source {
                 hir::MatchSource::ForLoopDesugar => {
                     // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
-                    let witness = match witnesses[0].node {
-                        PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
-                            &[ref pat] => &**pat,
+                    let witness = match *witnesses[0].kind {
+                        PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] {
+                            &[ref pat] => &pat.pattern,
                             _ => bug!(),
                         },
                         _ => bug!(),
                     };
-                    let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
-                        s.print_pat(witness)
-                    });
+                    let pattern_string = witness.to_string();
                     struct_span_err!(cx.tcx.sess, sp, E0297,
                         "refutable pattern in `for` loop binding: \
                                 `{}` not covered",
@@ -394,24 +381,23 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                         .emit();
                 },
                 _ => {
-                    let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
-                        hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
-                    }).collect();
                     const LIMIT: usize = 3;
-                    let joined_patterns = match pattern_strings.len() {
+                    let joined_patterns = match witnesses.len() {
                         0 => bug!(),
-                        1 => format!("`{}`", pattern_strings[0]),
+                        1 => format!("`{}`", witnesses[0]),
                         2...LIMIT => {
-                            let (tail, head) = pattern_strings.split_last().unwrap();
-                            format!("`{}`", head.join("`, `") + "` and `" + tail)
+                            let (tail, head) = witnesses.split_last().unwrap();
+                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                            format!("`{}` and `{}`", head.join("`, `"), tail)
                         },
                         _ => {
-                            let (head, tail) = pattern_strings.split_at(LIMIT);
+                            let (head, tail) = witnesses.split_at(LIMIT);
+                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
                             format!("`{}` and {} more", head.join("`, `"), tail.len())
                         }
                     };
 
-                    let label_text = match pattern_strings.len(){
+                    let label_text = match witnesses.len() {
                         1 => format!("pattern {} not covered", joined_patterns),
                         _ => format!("patterns {} not covered", joined_patterns)
                     };
index b24cd261dd58474730ee98fc242ef15f222e803f..8c8b2b5da36dc65d7e13a787e7bf349c09f44000 100644 (file)
@@ -16,6 +16,8 @@
 register_long_diagnostics! {
 
 E0001: r##"
+## Note: this error code is no longer emitted by the compiler.
+
 This error suggests that the expression arm corresponding to the noted pattern
 will never be reached as for all possible values of the expression being
 matched, one of the preceding patterns will match.
 
 For example, the following `match` block has too many arms:
 
-```compile_fail,E0001
+```
 match Some(0) {
     Some(bar) => {/* ... */}
-    None => {/* ... */}
+    x => {/* ... */} // This handles the `None` case
     _ => {/* ... */} // All possible cases have already been handled
 }
 ```
index c736b4865e73834ac605581ae7f5d4f89f5b39d6..6b8e0e34c1df63db42f70429e13631ce284b7b48 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
-use rustc::lint;
 
 use graphviz::IntoCow;
 use syntax::ast;
-use rustc::hir::{Expr, PatKind};
-use rustc::hir;
-use syntax::ptr::P;
-use syntax::codemap;
+use rustc::hir::{self, Expr};
 use syntax::attr::IntType;
-use syntax_pos::{self, Span};
+use syntax_pos::Span;
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
@@ -186,126 +182,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   expr: &Expr,
-                                   pat_id: ast::NodeId,
-                                   span: Span)
-                                   -> Result<P<hir::Pat>, DefId> {
-    let pat_ty = tcx.tables().expr_ty(expr);
-    debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
-    match pat_ty.sty {
-        ty::TyFloat(_) => {
-            tcx.sess.add_lint(
-                lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
-                pat_id,
-                span,
-                format!("floating point constants cannot be used in patterns"));
-        }
-        ty::TyAdt(adt_def, _) if adt_def.is_union() => {
-            // Matching on union fields is unsafe, we can't hide it in constants
-            tcx.sess.span_err(span, "cannot use unions in constant patterns");
-        }
-        ty::TyAdt(adt_def, _) => {
-            if !tcx.has_attr(adt_def.did, "structural_match") {
-                tcx.sess.add_lint(
-                    lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
-                    pat_id,
-                    span,
-                    format!("to use a constant of type `{}` \
-                             in a pattern, \
-                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                            tcx.item_path_str(adt_def.did),
-                            tcx.item_path_str(adt_def.did)));
-            }
-        }
-        _ => { }
-    }
-    let pat = match expr.node {
-        hir::ExprTup(ref exprs) =>
-            PatKind::Tuple(exprs.iter()
-                                .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                                .collect::<Result<_, _>>()?, None),
-
-        hir::ExprCall(ref callee, ref args) => {
-            let qpath = match callee.node {
-                hir::ExprPath(ref qpath) => qpath,
-                _ => bug!()
-            };
-            let def = tcx.tables().qpath_def(qpath, callee.id);
-            let ctor_path = if let hir::QPath::Resolved(_, ref path) = *qpath {
-                match def {
-                    Def::StructCtor(_, CtorKind::Fn) |
-                    Def::VariantCtor(_, CtorKind::Fn) => {
-                        Some(path.clone())
-                    }
-                    _ => None
-                }
-            } else {
-                None
-            };
-            match (def, ctor_path) {
-                (Def::Fn(..), None) | (Def::Method(..), None) => {
-                    PatKind::Lit(P(expr.clone()))
-                }
-                (_, Some(ctor_path)) => {
-                    let pats = args.iter()
-                                   .map(|expr| const_expr_to_pat(tcx, expr, pat_id, span))
-                                   .collect::<Result<_, _>>()?;
-                    PatKind::TupleStruct(hir::QPath::Resolved(None, ctor_path), pats, None)
-                }
-                _ => bug!()
-            }
-        }
-
-        hir::ExprStruct(ref qpath, ref fields, None) => {
-            let field_pats =
-                fields.iter()
-                      .map(|field| Ok(codemap::Spanned {
-                          span: syntax_pos::DUMMY_SP,
-                          node: hir::FieldPat {
-                              name: field.name.node,
-                              pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
-                              is_shorthand: false,
-                          },
-                      }))
-                      .collect::<Result<_, _>>()?;
-            PatKind::Struct(qpath.clone(), field_pats, false)
-        }
-
-        hir::ExprArray(ref exprs) => {
-            let pats = exprs.iter()
-                            .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                            .collect::<Result<_, _>>()?;
-            PatKind::Slice(pats, None, hir::HirVec::new())
-        }
-
-        hir::ExprPath(ref qpath) => {
-            let def = tcx.tables().qpath_def(qpath, expr.id);
-            match def {
-                Def::StructCtor(_, CtorKind::Const) |
-                Def::VariantCtor(_, CtorKind::Const) => {
-                    match expr.node {
-                        hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-                            PatKind::Path(hir::QPath::Resolved(None, path.clone()))
-                        }
-                        _ => bug!()
-                    }
-                }
-                Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                    let substs = Some(tcx.tables().node_id_item_substs(expr.id)
-                        .unwrap_or_else(|| tcx.intern_substs(&[])));
-                    let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
-                    return const_expr_to_pat(tcx, expr, pat_id, span);
-                },
-                _ => bug!(),
-            }
-        }
-
-        _ => PatKind::Lit(P(expr.clone()))
-    };
-    Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
-}
-
 pub fn report_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
index e93178c89c22b865b20cc054b73883b806c4ea19..42394f4745f6611067c0793bc2b78a6b7776e35e 100644 (file)
 
 use eval;
 
+use rustc::lint;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region};
+use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind};
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
 
+use std::fmt;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax_pos::Span;
@@ -27,7 +29,6 @@
 #[derive(Clone, Debug)]
 pub enum PatternError {
     StaticInPattern(Span),
-    BadConstInPattern(Span, DefId),
     ConstEval(eval::ConstEvalErr),
 }
 
@@ -67,6 +68,7 @@ pub enum PatternKind<'tcx> {
     /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
     Variant {
         adt_def: &'tcx AdtDef,
+        substs: &'tcx Substs<'tcx>,
         variant_index: usize,
         subpatterns: Vec<FieldPattern<'tcx>>,
     },
@@ -105,6 +107,158 @@ pub enum PatternKind<'tcx> {
     },
 }
 
+fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
+    match *value {
+        ConstVal::Float(ref x) => write!(f, "{}", x),
+        ConstVal::Integral(ref i) => write!(f, "{}", i),
+        ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
+        ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
+        ConstVal::Bool(b) => write!(f, "{:?}", b),
+        ConstVal::Char(c) => write!(f, "{:?}", c),
+        ConstVal::Struct(_) |
+        ConstVal::Tuple(_) |
+        ConstVal::Function(_) |
+        ConstVal::Array(..) |
+        ConstVal::Repeat(..) |
+        ConstVal::Dummy => bug!("{:?} not printable in a pattern", value)
+    }
+}
+
+impl<'tcx> fmt::Display for Pattern<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self.kind {
+            PatternKind::Wild => write!(f, "_"),
+            PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+                let is_mut = match mode {
+                    BindingMode::ByValue => mutability == Mutability::Mut,
+                    BindingMode::ByRef(_, bk) => {
+                        write!(f, "ref ")?;
+                        bk == BorrowKind::Mut
+                    }
+                };
+                if is_mut {
+                    write!(f, "mut ")?;
+                }
+                write!(f, "{}", name)?;
+                if let Some(ref subpattern) = *subpattern {
+                    write!(f, " @ {}", subpattern)?;
+                }
+                Ok(())
+            }
+            PatternKind::Variant { ref subpatterns, .. } |
+            PatternKind::Leaf { ref subpatterns } => {
+                let variant = match *self.kind {
+                    PatternKind::Variant { adt_def, variant_index, .. } => {
+                        Some(&adt_def.variants[variant_index])
+                    }
+                    _ => if let ty::TyAdt(adt, _) = self.ty.sty {
+                        Some(adt.struct_variant())
+                    } else {
+                        None
+                    }
+                };
+
+                let mut first = true;
+                let mut start_or_continue = || if first { first = false; "" } else { ", " };
+
+                if let Some(variant) = variant {
+                    write!(f, "{}", variant.name)?;
+
+                    // Only for TyAdt we can have `S {...}`,
+                    // which we handle separately here.
+                    if variant.ctor_kind == CtorKind::Fictive {
+                        write!(f, " {{ ")?;
+
+                        let mut printed = 0;
+                        for p in subpatterns {
+                            if let PatternKind::Wild = *p.pattern.kind {
+                                continue;
+                            }
+                            let name = variant.fields[p.field.index()].name;
+                            write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
+                            printed += 1;
+                        }
+
+                        if printed < variant.fields.len() {
+                            write!(f, "{}..", start_or_continue())?;
+                        }
+
+                        return write!(f, " }}");
+                    }
+                }
+
+                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+                if num_fields != 0 || variant.is_none() {
+                    write!(f, "(")?;
+                    for i in 0..num_fields {
+                        write!(f, "{}", start_or_continue())?;
+
+                        // Common case: the field is where we expect it.
+                        if let Some(p) = subpatterns.get(i) {
+                            if p.field.index() == i {
+                                write!(f, "{}", p.pattern)?;
+                                continue;
+                            }
+                        }
+
+                        // Otherwise, we have to go looking for it.
+                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                            write!(f, "{}", p.pattern)?;
+                        } else {
+                            write!(f, "_")?;
+                        }
+                    }
+                    write!(f, ")")?;
+                }
+
+                Ok(())
+            }
+            PatternKind::Deref { ref subpattern } => {
+                match self.ty.sty {
+                    ty::TyBox(_) => write!(f, "box ")?,
+                    ty::TyRef(_, mt) => {
+                        write!(f, "&")?;
+                        if mt.mutbl == hir::MutMutable {
+                            write!(f, "mut ")?;
+                        }
+                    }
+                    _ => bug!("{} is a bad Deref pattern type", self.ty)
+                }
+                write!(f, "{}", subpattern)
+            }
+            PatternKind::Constant { ref value } => {
+                print_const_val(value, f)
+            }
+            PatternKind::Range { ref lo, ref hi } => {
+                print_const_val(lo, f)?;
+                write!(f, "...")?;
+                print_const_val(hi, f)
+            }
+            PatternKind::Slice { ref prefix, ref slice, ref suffix } |
+            PatternKind::Array { ref prefix, ref slice, ref suffix } => {
+                let mut first = true;
+                let mut start_or_continue = || if first { first = false; "" } else { ", " };
+                write!(f, "[")?;
+                for p in prefix {
+                    write!(f, "{}{}", start_or_continue(), p)?;
+                }
+                if let Some(ref slice) = *slice {
+                    write!(f, "{}", start_or_continue())?;
+                    match *slice.kind {
+                        PatternKind::Wild => {}
+                        _ => write!(f, "{}", slice)?
+                    }
+                    write!(f, "..")?;
+                }
+                for p in suffix {
+                    write!(f, "{}{}", start_or_continue(), p)?;
+                }
+                write!(f, "]")
+            }
+        }
+    }
+}
+
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub errors: Vec<PatternError>,
@@ -133,64 +287,20 @@ pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
 
-            PatKind::Lit(ref value) => {
-                match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) {
-                    Ok(value) => {
-                        PatternKind::Constant { value: value }
-                    }
-                    Err(e) => {
-                        self.errors.push(PatternError::ConstEval(e));
-                        PatternKind::Wild
-                    }
-                }
-            }
+            PatKind::Lit(ref value) => self.lower_lit(value),
 
             PatKind::Range(ref lo, ref hi) => {
-                let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo);
-                if let Err(ref e_lo) = r_lo {
-                    self.errors.push(PatternError::ConstEval(e_lo.clone()));
-                }
-
-                let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi);
-                if let Err(ref e_hi) = r_hi {
-                    self.errors.push(PatternError::ConstEval(e_hi.clone()));
-                }
-
-                if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) {
-                    PatternKind::Range { lo: lo, hi: hi }
-                } else {
-                    PatternKind::Wild
+                match (self.lower_lit(lo), self.lower_lit(hi)) {
+                    (PatternKind::Constant { value: lo },
+                     PatternKind::Constant { value: hi }) => {
+                        PatternKind::Range { lo: lo, hi: hi }
+                    }
+                    _ => PatternKind::Wild
                 }
             }
 
             PatKind::Path(ref qpath) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                match def {
-                    Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                        let tcx = self.tcx.global_tcx();
-                        let substs = tcx.tables().node_id_item_substs(pat.id)
-                            .unwrap_or_else(|| tcx.intern_substs(&[]));
-                        match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                            Some((const_expr, _const_ty)) => {
-                                match eval::const_expr_to_pat(
-                                    tcx, const_expr, pat.id, pat.span)
-                                {
-                                    Ok(pat) => return self.lower_pattern(&pat),
-                                    Err(_) => {
-                                        self.errors.push(PatternError::BadConstInPattern(
-                                            pat.span, def_id));
-                                        PatternKind::Wild
-                                    }
-                                }
-                            }
-                            None => {
-                                self.errors.push(PatternError::StaticInPattern(pat.span));
-                                PatternKind::Wild
-                            }
-                        }
-                    }
-                    _ => self.lower_variant_or_leaf(def, vec![])
-                }
+                return self.lower_path(qpath, pat.id, pat.id, pat.span);
             }
 
             PatKind::Ref(ref subpattern, _) |
@@ -283,8 +393,7 @@ pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
 
             PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
                 let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
-                let adt_def = match pat_ty.sty {
+                let adt_def = match ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
                 };
@@ -298,13 +407,12 @@ pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                                        pattern: self.lower_pattern(field),
                                    })
                                    .collect();
-                self.lower_variant_or_leaf(def, subpatterns)
+                self.lower_variant_or_leaf(def, ty, subpatterns)
             }
 
             PatKind::Struct(ref qpath, ref fields, _) => {
                 let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
-                let adt_def = match pat_ty.sty {
+                let adt_def = match ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => {
                         span_bug!(
@@ -331,7 +439,7 @@ pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                           })
                           .collect();
 
-                self.lower_variant_or_leaf(def, subpatterns)
+                self.lower_variant_or_leaf(def, ty, subpatterns)
             }
         };
 
@@ -421,6 +529,7 @@ fn slice_or_array_pattern(
     fn lower_variant_or_leaf(
         &mut self,
         def: Def,
+        ty: Ty<'tcx>,
         subpatterns: Vec<FieldPattern<'tcx>>)
         -> PatternKind<'tcx>
     {
@@ -429,8 +538,14 @@ fn lower_variant_or_leaf(
                 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
                 let adt_def = self.tcx.lookup_adt_def(enum_id);
                 if adt_def.variants.len() > 1 {
+                    let substs = match ty.sty {
+                        TypeVariants::TyAdt(_, substs) => substs,
+                        TypeVariants::TyFnDef(_, substs, _) => substs,
+                        _ => bug!("inappropriate type for def: {:?}", ty.sty),
+                    };
                     PatternKind::Variant {
                         adt_def: adt_def,
+                        substs: substs,
                         variant_index: adt_def.variant_index_with_id(variant_id),
                         subpatterns: subpatterns,
                     }
@@ -447,6 +562,176 @@ fn lower_variant_or_leaf(
             _ => bug!()
         }
     }
+
+    fn lower_path(&mut self,
+                  qpath: &hir::QPath,
+                  id: ast::NodeId,
+                  pat_id: ast::NodeId,
+                  span: Span)
+                  -> Pattern<'tcx> {
+        let ty = self.tcx.tables().node_id_to_type(id);
+        let def = self.tcx.tables().qpath_def(qpath, id);
+        let kind = match def {
+            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                let tcx = self.tcx.global_tcx();
+                let substs = tcx.tables().node_id_item_substs(id)
+                    .unwrap_or_else(|| tcx.intern_substs(&[]));
+                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
+                    Some((const_expr, _const_ty)) => {
+                        return self.lower_const_expr(const_expr, pat_id, span);
+                    }
+                    None => {
+                        self.errors.push(PatternError::StaticInPattern(span));
+                        PatternKind::Wild
+                    }
+                }
+            }
+            _ => self.lower_variant_or_leaf(def, ty, vec![]),
+        };
+
+        Pattern {
+            span: span,
+            ty: ty,
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
+        match eval::eval_const_expr_checked(self.tcx.global_tcx(), expr) {
+            Ok(value) => {
+                PatternKind::Constant { value: value }
+            }
+            Err(e) => {
+                self.errors.push(PatternError::ConstEval(e));
+                PatternKind::Wild
+            }
+        }
+    }
+
+    fn lower_const_expr(&mut self,
+                        expr: &hir::Expr,
+                        pat_id: ast::NodeId,
+                        span: Span)
+                        -> Pattern<'tcx> {
+        let pat_ty = self.tcx.tables().expr_ty(expr);
+        debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
+        match pat_ty.sty {
+            ty::TyFloat(_) => {
+                self.tcx.sess.add_lint(
+                    lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
+                    pat_id,
+                    span,
+                    format!("floating point constants cannot be used in patterns"));
+            }
+            ty::TyAdt(adt_def, _) if adt_def.is_union() => {
+                // Matching on union fields is unsafe, we can't hide it in constants
+                self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
+            }
+            ty::TyAdt(adt_def, _) => {
+                if !self.tcx.has_attr(adt_def.did, "structural_match") {
+                    self.tcx.sess.add_lint(
+                        lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
+                        pat_id,
+                        span,
+                        format!("to use a constant of type `{}` \
+                                 in a pattern, \
+                                 `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                                self.tcx.item_path_str(adt_def.did),
+                                self.tcx.item_path_str(adt_def.did)));
+                }
+            }
+            _ => { }
+        }
+        let kind = match expr.node {
+            hir::ExprTup(ref exprs) => {
+                PatternKind::Leaf {
+                    subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: self.lower_const_expr(expr, pat_id, span)
+                        }
+                    }).collect()
+                }
+            }
+
+            hir::ExprCall(ref callee, ref args) => {
+                let qpath = match callee.node {
+                    hir::ExprPath(ref qpath) => qpath,
+                    _ => bug!()
+                };
+                let ty = self.tcx.tables().node_id_to_type(callee.id);
+                let def = self.tcx.tables().qpath_def(qpath, callee.id);
+                match def {
+                    Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
+                    _ => {
+                        let subpatterns = args.iter().enumerate().map(|(i, expr)| {
+                            FieldPattern {
+                                field: Field::new(i),
+                                pattern: self.lower_const_expr(expr, pat_id, span)
+                            }
+                        }).collect();
+                        self.lower_variant_or_leaf(def, ty, subpatterns)
+                    }
+                }
+            }
+
+            hir::ExprStruct(ref qpath, ref fields, None) => {
+                let def = self.tcx.tables().qpath_def(qpath, expr.id);
+                let pat_ty = self.tcx.tables().node_id_to_type(expr.id);
+                let adt_def = match pat_ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => {
+                        span_bug!(
+                            expr.span,
+                            "struct expr without ADT type");
+                    }
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                    fields.iter()
+                          .map(|field| {
+                              let index = variant_def.index_of_field_named(field.name.node);
+                              let index = index.unwrap_or_else(|| {
+                                  span_bug!(
+                                      expr.span,
+                                      "no field with name {:?}",
+                                      field.name);
+                              });
+                              FieldPattern {
+                                  field: Field::new(index),
+                                  pattern: self.lower_const_expr(&field.expr, pat_id, span),
+                              }
+                          })
+                          .collect();
+
+                self.lower_variant_or_leaf(def, pat_ty, subpatterns)
+            }
+
+            hir::ExprArray(ref exprs) => {
+                let pats = exprs.iter()
+                                .map(|expr| self.lower_const_expr(expr, pat_id, span))
+                                .collect();
+                PatternKind::Array {
+                    prefix: pats,
+                    slice: None,
+                    suffix: vec![]
+                }
+            }
+
+            hir::ExprPath(ref qpath) => {
+                return self.lower_path(qpath, expr.id, pat_id, span);
+            }
+
+            _ => self.lower_lit(expr)
+        };
+
+        Pattern {
+            span: span,
+            ty: pat_ty,
+            kind: Box::new(kind),
+        }
+    }
 }
 
 pub trait PatternFoldable<'tcx> : Sized {
@@ -500,8 +785,9 @@ fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal,
-    Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
+    Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
@@ -552,10 +838,12 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
             },
             PatternKind::Variant {
                 adt_def,
+                substs,
                 variant_index,
                 ref subpatterns,
             } => PatternKind::Variant {
                 adt_def: adt_def.fold_with(folder),
+                substs: substs.fold_with(folder),
                 variant_index: variant_index.fold_with(folder),
                 subpatterns: subpatterns.fold_with(folder)
             },
index 937cb3f600746cc7ace32a3cce6c5546858fa489..78af655852d1b0656ade7f7ce031ad0e38d71434 100644 (file)
@@ -19,6 +19,7 @@
 use std::iter::{self, IntoIterator, FromIterator};
 use std::slice;
 use std::vec;
+use std::collections::range::RangeArgument;
 
 use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
 
@@ -71,6 +72,19 @@ pub fn pop(&mut self) -> Option<A::Element> {
             AccumulateVec::Heap(ref mut vec) => vec.pop(),
         }
     }
+
+    pub fn drain<R>(&mut self, range: R) -> Drain<A>
+        where R: RangeArgument<usize>
+    {
+        match *self {
+            AccumulateVec::Array(ref mut v) => {
+                Drain::Array(v.drain(range))
+            },
+            AccumulateVec::Heap(ref mut v) => {
+                Drain::Heap(v.drain(range))
+            },
+        }
+    }
 }
 
 impl<A: Array> Deref for AccumulateVec<A> {
@@ -132,6 +146,31 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+pub enum Drain<'a, A: Array>
+        where A::Element: 'a
+{
+    Array(array_vec::Drain<'a, A>),
+    Heap(vec::Drain<'a, A::Element>),
+}
+
+impl<'a, A: Array> Iterator for Drain<'a, A> {
+    type Item = A::Element;
+
+    fn next(&mut self) -> Option<A::Element> {
+        match *self {
+            Drain::Array(ref mut drain) => drain.next(),
+            Drain::Heap(ref mut drain) => drain.next(),
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        match *self {
+            Drain::Array(ref drain) => drain.size_hint(),
+            Drain::Heap(ref drain) => drain.size_hint(),
+        }
+    }
+}
+
 impl<A: Array> IntoIterator for AccumulateVec<A> {
     type Item = A::Element;
     type IntoIter = IntoIter<A>;
index 631cf2cfcf6db1fdc63a2d666f340af980ef0312..844e9041d202984a8d312149510a10871b491775 100644 (file)
 
 use std::marker::Unsize;
 use std::iter::Extend;
-use std::ptr::{self, drop_in_place};
+use std::ptr::{self, drop_in_place, Shared};
 use std::ops::{Deref, DerefMut, Range};
 use std::hash::{Hash, Hasher};
 use std::slice;
 use std::fmt;
 use std::mem;
+use std::collections::range::RangeArgument;
 
 pub unsafe trait Array {
     type Element;
@@ -103,6 +104,44 @@ pub fn pop(&mut self) -> Option<A::Element> {
             None
         }
     }
+
+    pub fn drain<R>(&mut self, range: R) -> Drain<A>
+        where R: RangeArgument<usize>
+    {
+        // Memory safety
+        //
+        // When the Drain is first created, it shortens the length of
+        // the source vector to make sure no uninitalized or moved-from elements
+        // are accessible at all if the Drain's destructor never gets to run.
+        //
+        // Drain will ptr::read out the values to remove.
+        // When finished, remaining tail of the vec is copied back to cover
+        // the hole, and the vector length is restored to the new length.
+        //
+        let len = self.len();
+        let start = *range.start().unwrap_or(&0);
+        let end = *range.end().unwrap_or(&len);
+        assert!(start <= end);
+        assert!(end <= len);
+
+        unsafe {
+            // set self.vec length's to start, to be safe in case Drain is leaked
+            self.set_len(start);
+            // Use the borrow in the IterMut to indicate borrowing behavior of the
+            // whole Drain iterator (like &mut T).
+            let range_slice = {
+                let arr = &mut self.values as &mut [ManuallyDrop<_>];
+                slice::from_raw_parts_mut(arr.as_mut_ptr().offset(start as isize),
+                                          end - start)
+            };
+            Drain {
+                tail_start: end,
+                tail_len: len - end,
+                iter: range_slice.iter(),
+                array_vec: Shared::new(self as *mut _),
+            }
+        }
+    }
 }
 
 impl<A> Default for ArrayVec<A>
@@ -179,6 +218,51 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+pub struct Drain<'a, A: Array>
+        where A::Element: 'a
+{
+    tail_start: usize,
+    tail_len: usize,
+    iter: slice::Iter<'a, ManuallyDrop<A::Element>>,
+    array_vec: Shared<ArrayVec<A>>,
+}
+
+impl<'a, A: Array> Iterator for Drain<'a, A> {
+    type Item = A::Element;
+
+    #[inline]
+    fn next(&mut self) -> Option<A::Element> {
+        self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<'a, A: Array> Drop for Drain<'a, A> {
+    fn drop(&mut self) {
+        // exhaust self first
+        while let Some(_) = self.next() {}
+
+        if self.tail_len > 0 {
+            unsafe {
+                let source_array_vec = &mut **self.array_vec;
+                // memmove back untouched tail, update to new length
+                let start = source_array_vec.len();
+                let tail = self.tail_start;
+                {
+                    let mut arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
+                    let src = arr.as_ptr().offset(tail as isize);
+                    let dst = arr.as_mut_ptr().offset(start as isize);
+                    ptr::copy(src, dst, self.tail_len);
+                };
+                source_array_vec.set_len(start + self.tail_len);
+            }
+        }
+    }
+}
+
 impl<A: Array> IntoIterator for ArrayVec<A> {
     type Item = A::Element;
     type IntoIter = Iter<A>;
index d3ec674daed4da97d90fa62cfc6d2b5dd4289741..ee75a3596e18ab89e8b0d4ff61f35831d9e472d9 100644 (file)
@@ -25,6 +25,8 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(shared)]
+#![feature(collections_range)]
 #![feature(nonzero)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
index e9c14b4f99c2224847f41f98e7b97baa1f7fd09f..63abc09a07672c677a16720ea60eaa4c81c8dee0 100644 (file)
@@ -716,8 +716,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
                                                      is_proc_macro_crate,
                                                      is_test_crate,
                                                      num_crate_types,
-                                                     sess.diagnostic(),
-                                                     &sess.features.borrow())
+                                                     sess.diagnostic())
         });
     }
 
index a24edfaaac1c2fa3689aab276ab2f8bb47ecc0d3..efccc4abd43b8f7d3e96d19e01e6d4ee06b85d50 100644 (file)
@@ -165,6 +165,7 @@ macro_rules! add_lint_group {
                     DEAD_CODE,
                     UNUSED_MUT,
                     UNREACHABLE_CODE,
+                    UNREACHABLE_PATTERNS,
                     UNUSED_MUST_USE,
                     UNUSED_UNSAFE,
                     PATH_STATEMENTS,
index 95e955bd6833e85edf233bfd16d339b57c6b0815..570365c407f48b55b0e5f9ea6c7fd8d2dfb89c44 100644 (file)
 
 use rustc_i128::{i128, u128};
 
-register_long_diagnostics! {
-E0519: r##"
-It is not allowed to negate an unsigned integer.
-You can negate a signed integer and cast it to an
-unsigned integer or use the `!` operator.
-
-```
-let x: usize = -1isize as usize;
-let y: usize = !0;
-assert_eq!(x, y);
-```
-
-Alternatively you can use the `Wrapping` newtype
-or the `wrapping_neg` operation that all
-integral types support:
-
-```
-use std::num::Wrapping;
-let x: Wrapping<usize> = -Wrapping(1);
-let Wrapping(x) = x;
-let y: usize = 1.wrapping_neg();
-assert_eq!(x, y);
-```
-"##
-}
-
 declare_lint! {
     UNUSED_COMPARISONS,
     Warn,
@@ -109,24 +83,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
         match e.node {
             hir::ExprUnary(hir::UnNeg, ref expr) => {
-                if let hir::ExprLit(ref lit) = expr.node {
-                    match lit.node {
-                        ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
-                            forbid_unsigned_negation(cx, e.span);
-                        }
-                        ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-                            if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty {
-                                forbid_unsigned_negation(cx, e.span);
-                            }
-                        }
-                        _ => (),
-                    }
-                } else {
-                    let t = cx.tcx.tables().node_id_to_type(expr.id);
-                    if let ty::TyUint(_) = t.sty {
-                        forbid_unsigned_negation(cx, e.span);
-                    }
-                }
                 // propagate negation, if the negation itself isn't negated
                 if self.negated_expr_id != e.id {
                     self.negated_expr_id = expr.id;
@@ -369,13 +325,6 @@ fn is_comparison(binop: hir::BinOp) -> bool {
                 _ => false,
             }
         }
-
-        fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
-            cx.sess()
-                .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
-                .span_help(span, "use a cast or the `!` operator")
-                .emit();
-        }
     }
 }
 
index f4ccc01544aa660a045ab396d0361440ff013da4..3986cc507d4be3435cb42b2bcc7b8c7ab6eb311e 100644 (file)
@@ -21,7 +21,6 @@
 #![feature(conservative_impl_trait)]
 #![feature(core_intrinsics)]
 #![feature(proc_macro_internals)]
-#![feature(proc_macro_lib)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
index 71282dcf0ba0770e8cc6b0ef99e3ae6af918dc27..b071834122367421000e107fd2e06fd2324baba9 100644 (file)
@@ -26,6 +26,7 @@
 use build::matches::{Binding, MatchPair, Candidate};
 use hair::*;
 use rustc::mir::*;
+use rustc_data_structures::fx::FxHashSet;
 
 use std::mem;
 
@@ -93,11 +94,30 @@ fn simplify_match_pair<'pat>(&mut self,
             }
 
             PatternKind::Range { .. } |
-            PatternKind::Variant { .. } |
             PatternKind::Slice { .. } => {
                 Err(match_pair)
             }
 
+            PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
+                let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
+                    i == variant_index || {
+                        let mut visited = FxHashSet::default();
+                        let node_set = v.uninhabited_from(&mut visited,
+                                                          self.hir.tcx(),
+                                                          substs,
+                                                          adt_def.adt_kind());
+                        !node_set.is_empty()
+                    }
+                });
+                if irrefutable {
+                    let lvalue = match_pair.lvalue.downcast(adt_def, variant_index);
+                    candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns));
+                    Ok(())
+                } else {
+                    Err(match_pair)
+                }
+            },
+
             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
                 self.prefix_slice_suffix(&mut candidate.match_pairs,
                                          &match_pair.lvalue,
index cb449037aeba3eb9f610ec8ae32c8c095fd29b3c..8b4a013bad0a369be8bbc4c7b488bf1d3122dcae 100644 (file)
@@ -32,7 +32,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// It is a bug to call this with a simplifyable pattern.
     pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
         match *match_pair.pattern.kind {
-            PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
+            PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {
                 Test {
                     span: match_pair.pattern.span,
                     kind: TestKind::Switch {
@@ -451,7 +451,7 @@ pub fn sort_candidate<'pat>(&mut self,
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
             (&TestKind::Switch { adt_def: tested_adt_def, .. },
-             &PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => {
+             &PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
                 assert_eq!(adt_def, tested_adt_def);
                 let new_candidate =
                     self.candidate_after_variant_switch(match_pair_index,
index 41698574e0f1fa9233d7914cd1e8be8e41bc8124..2a4b2b515cc680e7bb67229d37ed1c77105b674e 100644 (file)
@@ -66,6 +66,7 @@ pub fn is_promotable(&self) -> bool {
 /// A "root candidate" for promotion, which will become the
 /// returned value in a promoted MIR, unless it's a subset
 /// of a larger candidate.
+#[derive(Debug)]
 pub enum Candidate {
     /// Borrow of a constant temporary.
     Ref(Location),
@@ -190,15 +191,12 @@ fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
     /// promoted MIR, recursing through temps.
     fn promote_temp(&mut self, temp: Local) -> Local {
         let old_keep_original = self.keep_original;
-        let (bb, stmt_idx) = match self.temps[temp] {
-            TempState::Defined {
-                location: Location { block, statement_index },
-                uses
-            } if uses > 0 => {
+        let loc = match self.temps[temp] {
+            TempState::Defined { location, uses } if uses > 0 => {
                 if uses > 1 {
                     self.keep_original = true;
                 }
-                (block, statement_index)
+                location
             }
             state =>  {
                 span_bug!(self.promoted.span, "{:?} not promotable: {:?}",
@@ -209,91 +207,80 @@ fn promote_temp(&mut self, temp: Local) -> Local {
             self.temps[temp] = TempState::PromotedOut;
         }
 
-        let no_stmts = self.source[bb].statements.len();
+        let no_stmts = self.source[loc.block].statements.len();
+        let new_temp = self.promoted.local_decls.push(
+            LocalDecl::new_temp(self.source.local_decls[temp].ty));
+
+        debug!("promote({:?} @ {:?}/{:?}, {:?})",
+               temp, loc, no_stmts, self.keep_original);
 
         // First, take the Rvalue or Call out of the source MIR,
         // or duplicate it, depending on keep_original.
-        let (mut rvalue, mut call) = (None, None);
-        let source_info = if stmt_idx < no_stmts {
-            let statement = &mut self.source[bb].statements[stmt_idx];
-            let rhs = match statement.kind {
-                StatementKind::Assign(_, ref mut rhs) => rhs,
-                _ => {
-                    span_bug!(statement.source_info.span, "{:?} is not an assignment",
-                              statement);
-                }
+        if loc.statement_index < no_stmts {
+            let (mut rvalue, source_info) = {
+                let statement = &mut self.source[loc.block].statements[loc.statement_index];
+                let rhs = match statement.kind {
+                    StatementKind::Assign(_, ref mut rhs) => rhs,
+                    _ => {
+                        span_bug!(statement.source_info.span, "{:?} is not an assignment",
+                                  statement);
+                    }
+                };
+
+                (if self.keep_original {
+                    rhs.clone()
+                } else {
+                    let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
+                    mem::replace(rhs, unit)
+                }, statement.source_info)
             };
-            if self.keep_original {
-                rvalue = Some(rhs.clone());
-            } else {
-                let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
-                rvalue = Some(mem::replace(rhs, unit));
-            }
-            statement.source_info
-        } else if self.keep_original {
-            let terminator = self.source[bb].terminator().clone();
-            call = Some(terminator.kind);
-            terminator.source_info
+
+            self.visit_rvalue(&mut rvalue, loc);
+            self.assign(new_temp, rvalue, source_info.span);
         } else {
-            let terminator = self.source[bb].terminator_mut();
-            let target = match terminator.kind {
-                TerminatorKind::Call {
-                    destination: ref mut dest @ Some(_),
-                    ref mut cleanup, ..
-                } => {
-                    // No cleanup necessary.
-                    cleanup.take();
-
-                    // We'll put a new destination in later.
-                    dest.take().unwrap().1
-                }
-                ref kind => {
-                    span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+            let mut terminator = if self.keep_original {
+                self.source[loc.block].terminator().clone()
+            } else {
+                let terminator = self.source[loc.block].terminator_mut();
+                let target = match terminator.kind {
+                    TerminatorKind::Call { destination: Some((_, target)), .. } => target,
+                    ref kind => {
+                        span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+                    }
+                };
+                Terminator {
+                    source_info: terminator.source_info,
+                    kind: mem::replace(&mut terminator.kind, TerminatorKind::Goto {
+                        target: target
+                    })
                 }
             };
-            call = Some(mem::replace(&mut terminator.kind, TerminatorKind::Goto {
-                target: target
-            }));
-            terminator.source_info
-        };
 
-        // Then, recurse for components in the Rvalue or Call.
-        if stmt_idx < no_stmts {
-            self.visit_rvalue(rvalue.as_mut().unwrap(), Location {
-                block: bb,
-                statement_index: stmt_idx
-            });
-        } else {
-            self.visit_terminator_kind(bb, call.as_mut().unwrap(), Location {
-                block: bb,
-                statement_index: no_stmts
-            });
-        }
-
-        let new_temp = self.promoted.local_decls.push(
-            LocalDecl::new_temp(self.source.local_decls[temp].ty));
-
-        // Inject the Rvalue or Call into the promoted MIR.
-        if stmt_idx < no_stmts {
-            self.assign(new_temp, rvalue.unwrap(), source_info.span);
-        } else {
             let last = self.promoted.basic_blocks().last().unwrap();
             let new_target = self.new_block();
-            let mut call = call.unwrap();
-            match call {
-                TerminatorKind::Call { ref mut destination, ..}  => {
-                    *destination = Some((Lvalue::Local(new_temp), new_target));
+
+            terminator.kind = match terminator.kind {
+                TerminatorKind::Call { mut func, mut args, .. } => {
+                    self.visit_operand(&mut func, loc);
+                    for arg in &mut args {
+                        self.visit_operand(arg, loc);
+                    }
+                    TerminatorKind::Call {
+                        func: func,
+                        args: args,
+                        cleanup: None,
+                        destination: Some((Lvalue::Local(new_temp), new_target))
+                    }
                 }
-                _ => bug!()
-            }
-            let terminator = self.promoted[last].terminator_mut();
-            terminator.source_info.span = source_info.span;
-            terminator.kind = call;
-        }
+                ref kind => {
+                    span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+                }
+            };
 
-        // Restore the old duplication state.
-        self.keep_original = old_keep_original;
+            *self.promoted[last].terminator_mut() = terminator;
+        };
 
+        self.keep_original = old_keep_original;
         new_temp
     }
 
@@ -355,6 +342,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     mut temps: IndexVec<Local, TempState>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
+    debug!("promote_candidates({:?})", candidates);
     for candidate in candidates.into_iter().rev() {
         let (span, ty) = match candidate {
             Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
index 893478a933182988d45c69552d0f65f412024290..d144651fb7db62e3e31391256b232e86f3ece4b6 100644 (file)
@@ -993,9 +993,9 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     Entry::Vacant(entry) => {
                         // Guard against `const` recursion.
                         entry.insert(Qualif::RECURSIVE);
+                        Mode::Const
                     }
                 }
-                Mode::Const
             }
             MirSource::Static(_, hir::MutImmutable) => Mode::Static,
             MirSource::Static(_, hir::MutMutable) => Mode::StaticMut,
index b7908f0c0edded5a92e26cd17a00ab01062d7914..1eeb356480cf2e9cca0e2edddfe2ccbf47f12f19 100644 (file)
@@ -2336,20 +2336,19 @@ fn resolve_qpath(&mut self,
             PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
         };
 
-        if path.len() == 1 || global_by_default || result.base_def == Def::Err {
-            return Some(result);
-        }
-
-        let unqualified_result = {
-            match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
-                PathResult::NonModule(path_res) => path_res.base_def,
-                PathResult::Module(module) => module.def().unwrap(),
-                _ => return Some(result),
+        if path.len() > 1 && !global_by_default && result.base_def != Def::Err &&
+           path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" {
+            let unqualified_result = {
+                match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
+                    PathResult::NonModule(path_res) => path_res.base_def,
+                    PathResult::Module(module) => module.def().unwrap(),
+                    _ => return Some(result),
+                }
+            };
+            if result.base_def == unqualified_result {
+                let lint = lint::builtin::UNUSED_QUALIFICATIONS;
+                self.session.add_lint(lint, id, span, "unnecessary qualification".to_string());
             }
-        };
-        if result.base_def == unqualified_result && path[0].name != "$crate" {
-            let lint = lint::builtin::UNUSED_QUALIFICATIONS;
-            self.session.add_lint(lint, id, span, "unnecessary qualification".to_string());
         }
 
         Some(result)
index 41d8f16b88dfd4849200d72eaf157f564c717e30..91197e53d3c82523ab2559dc3b63bb556098be93 100644 (file)
@@ -21,6 +21,7 @@
 use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::*;
+use rustc::util::nodemap::FxHashSet;
 
 use syntax::ast::{Ident, NodeId};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
@@ -728,7 +729,12 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
 
         let mut reexports = Vec::new();
         if module as *const _ == self.graph_root as *const _ {
-            reexports = mem::replace(&mut self.macro_exports, Vec::new());
+            let mut exported_macro_names = FxHashSet();
+            for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() {
+                if exported_macro_names.insert(export.name) {
+                    reexports.push(export);
+                }
+            }
         }
 
         for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
index b3eec5d66c4683c9dac02d81f6216200e20810b9..ad4bb0fce22ad699922cb2b627f1bd54f7399a44 100644 (file)
@@ -10,7 +10,8 @@
 
 use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
 use base;
-use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
+use builder::Builder;
+use common::{type_is_fat_ptr, C_uint};
 use context::CrateContext;
 use cabi_x86;
 use cabi_x86_64;
@@ -236,7 +237,7 @@ pub fn memory_ty(&self, ccx: &CrateContext) -> Type {
     /// lvalue for the original Rust type of this argument/return.
     /// Can be used for both storing formal arguments into Rust variables
     /// or results of call/invoke instructions into their destinations.
-    pub fn store(&self, bcx: &BlockAndBuilder, mut val: ValueRef, dst: ValueRef) {
+    pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
         if self.is_ignore() {
             return;
         }
@@ -251,11 +252,8 @@ pub fn store(&self, bcx: &BlockAndBuilder, mut val: ValueRef, dst: ValueRef) {
             let can_store_through_cast_ptr = false;
             if can_store_through_cast_ptr {
                 let cast_dst = bcx.pointercast(dst, ty.ptr_to());
-                let store = bcx.store(val, cast_dst);
                 let llalign = llalign_of_min(ccx, self.ty);
-                unsafe {
-                    llvm::LLVMSetAlignment(store, llalign);
-                }
+                bcx.store(val, cast_dst, Some(llalign));
             } else {
                 // The actual return type is a struct, but the ABI
                 // adaptation code has cast it into some scalar type.  The
@@ -272,11 +270,11 @@ pub fn store(&self, bcx: &BlockAndBuilder, mut val: ValueRef, dst: ValueRef) {
                 //   bitcasting to the struct type yields invalid cast errors.
 
                 // We instead thus allocate some scratch space...
-                let llscratch = bcx.fcx().alloca(ty, "abi_cast");
+                let llscratch = bcx.alloca(ty, "abi_cast");
                 base::Lifetime::Start.call(bcx, llscratch);
 
                 // ...where we first store the value...
-                bcx.store(val, llscratch);
+                bcx.store(val, llscratch, None);
 
                 // ...and then memcpy it to the intended destination.
                 base::call_memcpy(bcx,
@@ -292,18 +290,18 @@ pub fn store(&self, bcx: &BlockAndBuilder, mut val: ValueRef, dst: ValueRef) {
             if self.original_ty == Type::i1(ccx) {
                 val = bcx.zext(val, Type::i8(ccx));
             }
-            bcx.store(val, dst);
+            bcx.store(val, dst, None);
         }
     }
 
-    pub fn store_fn_arg(&self, bcx: &BlockAndBuilder, idx: &mut usize, dst: ValueRef) {
+    pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) {
         if self.pad.is_some() {
             *idx += 1;
         }
         if self.is_ignore() {
             return;
         }
-        let val = llvm::get_param(bcx.fcx().llfn, *idx as c_uint);
+        let val = llvm::get_param(bcx.llfn(), *idx as c_uint);
         *idx += 1;
         self.store(bcx, val, dst);
     }
index 31a5538a3c1179f3126eb279fffbc59ae9427d37..c3b9a56ac9778569b4d1e4e835ff2571fbcae58d 100644 (file)
 use rustc::ty::layout;
 use rustc::ty::{self, Ty, AdtKind};
 use common::*;
-use glue;
+use builder::Builder;
 use base;
 use machine;
 use monomorphize;
 use type_::Type;
 use type_of;
-use value::Value;
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum BranchKind {
-    Switch,
-    Single
-}
-
-#[derive(Copy, Clone)]
-pub struct MaybeSizedValue {
-    pub value: ValueRef,
-    pub meta: ValueRef,
-}
-
-impl MaybeSizedValue {
-    pub fn sized(value: ValueRef) -> MaybeSizedValue {
-        MaybeSizedValue {
-            value: value,
-            meta: std::ptr::null_mut()
-        }
-    }
-
-    pub fn unsized_(value: ValueRef, meta: ValueRef) -> MaybeSizedValue {
-        MaybeSizedValue {
-            value: value,
-            meta: meta
-        }
-    }
-
-    pub fn has_meta(&self) -> bool {
-        !self.meta.is_null()
-    }
-}
 
 /// Given an enum, struct, closure, or tuple, extracts fields.
 /// Treats closures as a struct with one variant.
 /// `empty_if_no_variants` is a switch to deal with empty enums.
 /// If true, `variant_index` is disregarded and an empty Vec returned in this case.
-fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
-                            variant_index: usize,
-                            empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
+pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
+                                variant_index: usize,
+                                empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
     match t.sty {
         ty::TyAdt(ref def, _) if def.variants.len() == 0 && empty_if_no_variants => {
             Vec::default()
@@ -300,28 +267,6 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>
     }
 }
 
-/// Obtain a representation of the discriminant sufficient to translate
-/// destructuring; this may or may not involve the actual discriminant.
-pub fn trans_switch<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
-    t: Ty<'tcx>,
-    scrutinee: ValueRef,
-    range_assert: bool
-) -> (BranchKind, Option<ValueRef>) {
-    let l = bcx.ccx.layout_of(t);
-    match *l {
-        layout::CEnum { .. } | layout::General { .. } |
-        layout::RawNullablePointer { .. } | layout::StructWrappedNullablePointer { .. } => {
-            (BranchKind::Switch, Some(trans_get_discr(bcx, t, scrutinee, None, range_assert)))
-        }
-        layout::Univariant { .. } | layout::UntaggedUnion { .. } => {
-            // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
-            (BranchKind::Single, None)
-        },
-        _ => bug!("{} is not an enum.", t)
-    }
-}
-
 pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
     match *l {
         layout::CEnum { signed, .. }=> signed,
@@ -331,7 +276,7 @@ pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
 
 /// Obtain the actual discriminant of a value.
 pub fn trans_get_discr<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     t: Ty<'tcx>,
     scrutinee: ValueRef,
     cast_to: Option<Type>,
@@ -358,7 +303,7 @@ pub fn trans_get_discr<'a, 'tcx>(
         layout::RawNullablePointer { nndiscr, .. } => {
             let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
             let llptrty = type_of::sizing_type_of(bcx.ccx,
-                monomorphize::field_ty(bcx.ccx.tcx(), substs,
+                monomorphize::field_ty(bcx.tcx(), substs,
                 &def.variants[nndiscr as usize].fields[0]));
             bcx.icmp(cmp, bcx.load(scrutinee), C_null(llptrty))
         }
@@ -374,7 +319,7 @@ pub fn trans_get_discr<'a, 'tcx>(
 }
 
 fn struct_wrapped_nullable_bitdiscr(
-    bcx: &BlockAndBuilder,
+    bcx: &Builder,
     nndiscr: u64,
     discrfield: &layout::FieldPath,
     scrutinee: ValueRef
@@ -387,7 +332,7 @@ fn struct_wrapped_nullable_bitdiscr(
 }
 
 /// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: &BlockAndBuilder, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
+fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
               range_assert: bool)
     -> ValueRef {
     let llty = Type::from_integer(bcx.ccx, ity);
@@ -415,7 +360,7 @@ fn load_discr(bcx: &BlockAndBuilder, ity: layout::Integer, ptr: ValueRef, min: u
 /// discriminant-like value returned by `trans_switch`.
 ///
 /// This should ideally be less tightly tied to `_match`.
-pub fn trans_case<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -> ValueRef {
+pub fn trans_case<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -> ValueRef {
     let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum { discr, .. }
@@ -435,19 +380,17 @@ pub fn trans_case<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, t: Ty<'tcx>, value:
 
 /// Set the discriminant for a new value of the given case of the given
 /// representation.
-pub fn trans_set_discr<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr
-) {
+pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
     let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum{ discr, min, max, .. } => {
             assert_discr_in_range(Disr(min), Disr(max), to);
             bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
-                  val);
+                  val, None);
         }
         layout::General{ discr, .. } => {
             bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
-                  bcx.struct_gep(val, 0));
+                  bcx.struct_gep(val, 0), None);
         }
         layout::Univariant { .. }
         | layout::UntaggedUnion { .. }
@@ -458,7 +401,7 @@ pub fn trans_set_discr<'a, 'tcx>(
             let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
             if to.0 != nndiscr {
                 let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
-                bcx.store(C_null(llptrty), val);
+                bcx.store(C_null(llptrty), val, None);
             }
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
@@ -476,7 +419,7 @@ pub fn trans_set_discr<'a, 'tcx>(
                     let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
                     let llptrptr = bcx.gepi(val, &path[..]);
                     let llptrty = val_ty(llptrptr).element_type();
-                    bcx.store(C_null(llptrty), llptrptr);
+                    bcx.store(C_null(llptrty), llptrptr, None);
                 }
             }
         }
@@ -484,11 +427,11 @@ pub fn trans_set_discr<'a, 'tcx>(
     }
 }
 
-fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>) -> bool {
+fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool {
     bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
 }
 
-fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
+pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
     if min <= max {
         assert!(min <= discr && discr <= max)
     } else {
@@ -496,303 +439,6 @@ fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
     }
 }
 
-/// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
-    t: Ty<'tcx>,
-    val: MaybeSizedValue,
-    discr: Disr,
-    ix: usize
-) -> ValueRef {
-    let l = bcx.ccx.layout_of(t);
-    debug!("trans_field_ptr on {} represented as {:#?}", t, l);
-    // Note: if this ever needs to generate conditionals (e.g., if we
-    // decide to do some kind of cdr-coding-like non-unique repr
-    // someday), it will need to return a possibly-new bcx as well.
-    match *l {
-        layout::Univariant { ref variant, .. } => {
-            assert_eq!(discr, Disr(0));
-            struct_field_ptr(bcx, &variant,
-             &compute_fields(bcx.ccx, t, 0, false),
-             val, ix, false)
-        }
-        layout::Vector { count, .. } => {
-            assert_eq!(discr.0, 0);
-            assert!((ix as u64) < count);
-            bcx.struct_gep(val.value, ix)
-        }
-        layout::General { discr: d, ref variants, .. } => {
-            let mut fields = compute_fields(bcx.ccx, t, discr.0 as usize, false);
-            fields.insert(0, d.to_ty(&bcx.ccx.tcx(), false));
-            struct_field_ptr(bcx, &variants[discr.0 as usize],
-             &fields,
-             val, ix + 1, true)
-        }
-        layout::UntaggedUnion { .. } => {
-            let fields = compute_fields(bcx.ccx, t, 0, false);
-            let ty = type_of::in_memory_type_of(bcx.ccx, fields[ix]);
-            bcx.pointercast(val.value, ty.ptr_to())
-        }
-        layout::RawNullablePointer { nndiscr, .. } |
-        layout::StructWrappedNullablePointer { nndiscr,  .. } if discr.0 != nndiscr => {
-            let nullfields = compute_fields(bcx.ccx, t, (1-nndiscr) as usize, false);
-            // The unit-like case might have a nonzero number of unit-like fields.
-            // (e.d., Result of Either with (), as one side.)
-            let ty = type_of::type_of(bcx.ccx, nullfields[ix]);
-            assert_eq!(machine::llsize_of_alloc(bcx.ccx, ty), 0);
-            bcx.pointercast(val.value, ty.ptr_to())
-        }
-        layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
-            assert_eq!(ix, 0);
-            assert_eq!(discr.0, nndiscr);
-            let ty = type_of::type_of(bcx.ccx, nnty);
-            bcx.pointercast(val.value, ty.ptr_to())
-        }
-        layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
-            assert_eq!(discr.0, nndiscr);
-            struct_field_ptr(bcx, &nonnull,
-             &compute_fields(bcx.ccx, t, discr.0 as usize, false),
-             val, ix, false)
-        }
-        _ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
-    }
-}
-
-fn struct_field_ptr<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
-    st: &layout::Struct,
-    fields: &Vec<Ty<'tcx>>,
-    val: MaybeSizedValue,
-    ix: usize,
-    needs_cast: bool
-) -> ValueRef {
-    let fty = fields[ix];
-    let ccx = bcx.ccx;
-
-    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);
-        bcx.pointercast(val.value, real_ty.ptr_to())
-    } else {
-        val.value
-    };
-
-    // Simple case - we can just GEP the field
-    //   * First field - Always aligned properly
-    //   * Packed struct - There is no alignment padding
-    //   * 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);
-    }
-
-    // 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);
-        }
-        _ => ()
-    }
-
-    // There's no metadata available, log the case and just do the GEP.
-    if !val.has_meta() {
-        debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
-               ix, Value(ptr_val));
-        return bcx.struct_gep(ptr_val, ix);
-    }
-
-    // We need to get the pointer manually now.
-    // We do this by casting to a *i8, then offsetting it by the appropriate amount.
-    // We do this instead of, say, simply adjusting the pointer from the result of a GEP
-    // because the field may have an arbitrary alignment in the LLVM representation
-    // anyway.
-    //
-    // To demonstrate:
-    //   struct Foo<T: ?Sized> {
-    //      x: u16,
-    //      y: T
-    //   }
-    //
-    // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
-    // the `y` field has 16-bit alignment.
-
-    let meta = val.meta;
-
-
-    let offset = st.offsets[ix].bytes();
-    let unaligned_offset = C_uint(bcx.ccx, offset);
-
-    // Get the alignment of the field
-    let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
-
-    // Bump the unaligned offset up to the appropriate alignment using the
-    // following expression:
-    //
-    //   (unaligned offset + (align - 1)) & -align
-
-    // Calculate offset
-    let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
-    let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
-                         bcx.neg(align));
-
-    debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
-
-    // Cast and adjust pointer
-    let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx));
-    let byte_ptr = bcx.gep(byte_ptr, &[offset]);
-
-    // Finally, cast back to the type expected
-    let ll_fty = type_of::in_memory_type_of(bcx.ccx, fty);
-    debug!("struct_field_ptr: Field type is {:?}", ll_fty);
-    bcx.pointercast(byte_ptr, ll_fty.ptr_to())
-}
-
-/// Construct a constant value, suitable for initializing a
-/// GlobalVariable, given a case and constant values for its fields.
-/// Note that this may have a different LLVM type (and different
-/// alignment!) from the representation's `type_of`, so it needs a
-/// pointer cast before use.
-///
-/// The LLVM type system does not directly support unions, and only
-/// pointers can be bitcast, so a constant (and, by extension, the
-/// GlobalVariable initialized by it) will have a type that can vary
-/// depending on which case of an enum it is.
-///
-/// To understand the alignment situation, consider `enum E { V64(u64),
-/// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
-/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
-/// i32, i32}`, which is 4-byte aligned.
-///
-/// Currently the returned value has the same size as the type, but
-/// this could be changed in the future to avoid allocating unnecessary
-/// space after values of shorter-than-maximum cases.
-pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: Disr,
-                             vals: &[ValueRef]) -> ValueRef {
-    let l = ccx.layout_of(t);
-    let dl = &ccx.tcx().data_layout;
-    match *l {
-        layout::CEnum { discr: d, min, max, .. } => {
-            assert_eq!(vals.len(), 0);
-            assert_discr_in_range(Disr(min), Disr(max), discr);
-            C_integral(Type::from_integer(ccx, d), discr.0, true)
-        }
-        layout::General { discr: d, ref variants, .. } => {
-            let variant = &variants[discr.0 as usize];
-            let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
-            let mut vals_with_discr = vec![lldiscr];
-            vals_with_discr.extend_from_slice(vals);
-            let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
-            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
-            if needed_padding > 0 {
-                contents.push(padding(ccx, needed_padding));
-            }
-            C_struct(ccx, &contents[..], false)
-        }
-        layout::UntaggedUnion { ref variants, .. }=> {
-            assert_eq!(discr, Disr(0));
-            let contents = build_const_union(ccx, variants, vals[0]);
-            C_struct(ccx, &contents, variants.packed)
-        }
-        layout::Univariant { ref variant, .. } => {
-            assert_eq!(discr, Disr(0));
-            let contents = build_const_struct(ccx, &variant, vals);
-            C_struct(ccx, &contents[..], variant.packed)
-        }
-        layout::Vector { .. } => {
-            C_vector(vals)
-        }
-        layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(ccx, t, nndiscr as usize, false)[0];
-            if discr.0 == nndiscr {
-                assert_eq!(vals.len(), 1);
-                vals[0]
-            } else {
-                C_null(type_of::sizing_type_of(ccx, nnty))
-            }
-        }
-        layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
-            if discr.0 == nndiscr {
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
-            } else {
-                let fields = compute_fields(ccx, t, nndiscr as usize, false);
-                let vals = fields.iter().map(|&ty| {
-                    // Always use null even if it's not the `discrfield`th
-                    // field; see #8506.
-                    C_null(type_of::sizing_type_of(ccx, ty))
-                }).collect::<Vec<ValueRef>>();
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
-            }
-        }
-        _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
-    }
-}
-
-/// Building structs is a little complicated, because we might need to
-/// insert padding if a field's value is less aligned than its type.
-///
-/// Continuing the example from `trans_const`, a value of type `(u32,
-/// E)` should have the `E` at offset 8, but if that field's
-/// initializer is 4-byte aligned then simply translating the tuple as
-/// a two-element struct will locate it at offset 4, and accesses to it
-/// will read the wrong memory.
-fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                st: &layout::Struct,
-                                vals: &[ValueRef])
-                                -> Vec<ValueRef> {
-    assert_eq!(vals.len(), st.offsets.len());
-
-    if vals.len() == 0 {
-        return Vec::new();
-    }
-
-    // offset of current value
-    let mut offset = 0;
-    let mut cfields = Vec::new();
-    cfields.reserve(st.offsets.len()*2);
-
-    let parts = st.field_index_by_increasing_offset().map(|i| {
-        (&vals[i], st.offsets[i].bytes())
-    });
-    for (&val, target_offset) in parts {
-        if offset < target_offset {
-            cfields.push(padding(ccx, target_offset - offset));
-            offset = target_offset;
-        }
-        assert!(!is_undef(val));
-        cfields.push(val);
-        offset += machine::llsize_of_alloc(ccx, val_ty(val));
-    }
-
-    if offset < st.stride().bytes() {
-        cfields.push(padding(ccx, st.stride().bytes() - offset));
-    }
-
-    cfields
-}
-
-fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               un: &layout::Union,
-                               field_val: ValueRef)
-                               -> Vec<ValueRef> {
-    let mut cfields = vec![field_val];
-
-    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
-    let size = un.stride().bytes();
-    if offset != size {
-        cfields.push(padding(ccx, size - offset));
-    }
-
-    cfields
-}
-
-fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
-    C_undef(Type::array(&Type::i8(ccx), size))
-}
-
 // FIXME this utility routine should be somewhere more general
 #[inline]
 fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
index d6385e1ca156263994ec0ef4d35c030b13a23416..c95d414701876ef6a4d4c9e19d57b12925db5bc5 100644 (file)
@@ -15,6 +15,7 @@
 use common::*;
 use type_of;
 use type_::Type;
+use builder::Builder;
 
 use rustc::hir;
 use rustc::ty::Ty;
@@ -25,7 +26,7 @@
 
 // Take an inline assembly expression and splat it out via LLVM
 pub fn trans_inline_asm<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     ia: &hir::InlineAsm,
     outputs: Vec<(ValueRef, Ty<'tcx>)>,
     mut inputs: Vec<ValueRef>
@@ -105,7 +106,7 @@ pub fn trans_inline_asm<'a, 'tcx>(
     let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
     for (i, (_, &(val, _))) in outputs.enumerate() {
         let v = if num_outputs == 1 { r } else { bcx.extract_value(r, i) };
-        bcx.store(v, val);
+        bcx.store(v, val, None);
     }
 
     // Store expn_id in a metadata node so we can map LLVM errors
index 47b76658bdd1481689e5c960e8c7862004c232df..4cdde24ed48b568a1f69c6cd4690cc62f29ce010 100644 (file)
@@ -37,8 +37,9 @@
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use middle::lang_items::StartFnLangItem;
 use rustc::ty::subst::Substs;
+use rustc::mir::tcx::LvalueTy;
 use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::dep_graph::{DepNode, WorkProduct};
 use rustc::hir::map as hir_map;
 use rustc_incremental::IncrementalHashesMap;
 use session::{self, DataTypeKind, Session};
 use abi::{self, Abi, FnType};
+use mir::lvalue::LvalueRef;
 use adt;
 use attributes;
 use builder::Builder;
 use callee::{Callee};
-use common::{BlockAndBuilder, C_bool, C_bytes_in_context, C_i32, C_uint};
+use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
 use collector::{self, TransItemCollectionMode};
 use common::{C_struct_in_context, C_u64, C_undef};
-use common::{CrateContext, FunctionContext};
+use common::CrateContext;
 use common::{fulfill_obligation};
 use common::{type_is_zero_size, val_ty};
 use common;
@@ -161,7 +163,7 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate {
 }
 
 pub fn compare_simd_types<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     lhs: ValueRef,
     rhs: ValueRef,
     t: Ty<'tcx>,
@@ -218,7 +220,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
 
 /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
 pub fn unsize_thin_ptr<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     src: ValueRef,
     src_ty: Ty<'tcx>,
     dst_ty: Ty<'tcx>
@@ -242,7 +244,7 @@ pub fn unsize_thin_ptr<'a, 'tcx>(
 
 /// Coerce `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty` and store the result in `dst`
-pub fn coerce_unsized_into<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                      src: ValueRef,
                                      src_ty: Ty<'tcx>,
                                      dst: ValueRef,
@@ -278,8 +280,8 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                 monomorphize::field_ty(bcx.tcx(), substs_b, f)
             });
 
-            let src = adt::MaybeSizedValue::sized(src);
-            let dst = adt::MaybeSizedValue::sized(dst);
+            let src = LvalueRef::new_sized_ty(src, src_ty);
+            let dst = LvalueRef::new_sized_ty(dst, dst_ty);
 
             let iter = src_fields.zip(dst_fields).enumerate();
             for (i, (src_fty, dst_fty)) in iter {
@@ -287,10 +289,10 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                     continue;
                 }
 
-                let src_f = adt::trans_field_ptr(bcx, src_ty, src, Disr(0), i);
-                let dst_f = adt::trans_field_ptr(bcx, dst_ty, dst, Disr(0), i);
+                let src_f = src.trans_field_ptr(bcx, i);
+                let dst_f = dst.trans_field_ptr(bcx, i);
                 if src_fty == dst_fty {
-                    memcpy_ty(bcx, dst_f, src_f, src_fty);
+                    memcpy_ty(bcx, dst_f, src_f, src_fty, None);
                 } else {
                     coerce_unsized_into(bcx, src_f, src_fty, dst_f, dst_fty);
                 }
@@ -322,7 +324,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
 }
 
 pub fn cast_shift_expr_rhs(
-    cx: &BlockAndBuilder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef
+    cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef
 ) -> ValueRef {
     cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
 }
@@ -421,7 +423,7 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> V
 
 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values.
-pub fn store_ty<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
+pub fn store_ty<'a, 'tcx>(cx: &Builder<'a, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
     debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
 
     if common::type_is_fat_ptr(cx.ccx, t) {
@@ -429,18 +431,18 @@ pub fn store_ty<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>, v: ValueRef, dst: Valu
         let llextra = cx.extract_value(v, abi::FAT_PTR_EXTRA);
         store_fat_ptr(cx, lladdr, llextra, dst, t);
     } else {
-        cx.store(from_immediate(cx, v), dst);
+        cx.store(from_immediate(cx, v), dst, None);
     }
 }
 
-pub fn store_fat_ptr<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
+pub fn store_fat_ptr<'a, 'tcx>(cx: &Builder<'a, 'tcx>,
                                data: ValueRef,
                                extra: ValueRef,
                                dst: ValueRef,
                                _ty: Ty<'tcx>) {
     // FIXME: emit metadata
-    cx.store(data, get_dataptr(cx, dst));
-    cx.store(extra, get_meta(cx, dst));
+    cx.store(data, get_dataptr(cx, dst), None);
+    cx.store(extra, get_meta(cx, dst), None);
 }
 
 pub fn load_fat_ptr<'a, 'tcx>(
@@ -459,7 +461,7 @@ pub fn load_fat_ptr<'a, 'tcx>(
     (ptr, meta)
 }
 
-pub fn from_immediate(bcx: &BlockAndBuilder, val: ValueRef) -> ValueRef {
+pub fn from_immediate(bcx: &Builder, val: ValueRef) -> ValueRef {
     if val_ty(val) == Type::i1(bcx.ccx) {
         bcx.zext(val, Type::i8(bcx.ccx))
     } else {
@@ -467,7 +469,7 @@ pub fn from_immediate(bcx: &BlockAndBuilder, val: ValueRef) -> ValueRef {
     }
 }
 
-pub fn to_immediate(bcx: &BlockAndBuilder, val: ValueRef, ty: Ty) -> ValueRef {
+pub fn to_immediate(bcx: &Builder, val: ValueRef, ty: Ty) -> ValueRef {
     if ty.is_bool() {
         bcx.trunc(val, Type::i1(bcx.ccx))
     } else {
@@ -524,7 +526,11 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
 }
 
 pub fn memcpy_ty<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>
+    bcx: &Builder<'a, 'tcx>,
+    dst: ValueRef,
+    src: ValueRef,
+    t: Ty<'tcx>,
+    align: Option<u32>,
 ) {
     let ccx = bcx.ccx;
 
@@ -532,17 +538,10 @@ pub fn memcpy_ty<'a, 'tcx>(
         return;
     }
 
-    if t.is_structural() {
-        let llty = type_of::type_of(ccx, t);
-        let llsz = llsize_of(ccx, llty);
-        let llalign = type_of::align_of(ccx, t);
-        call_memcpy(bcx, dst, src, llsz, llalign as u32);
-    } else if common::type_is_fat_ptr(bcx.ccx, t) {
-        let (data, extra) = load_fat_ptr(bcx, src, t);
-        store_fat_ptr(bcx, data, extra, dst, t);
-    } else {
-        store_ty(bcx, load_ty(bcx, src, t), dst, t);
-    }
+    let llty = type_of::type_of(ccx, t);
+    let llsz = llsize_of(ccx, llty);
+    let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t));
+    call_memcpy(bcx, dst, src, llsz, llalign as u32);
 }
 
 pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
@@ -558,11 +557,6 @@ pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
     b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None)
 }
 
-pub fn alloc_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
-    assert!(!ty.has_param_types());
-    bcx.fcx().alloca(type_of::type_of(bcx.ccx, ty), name)
-}
-
 pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
     let _s = if ccx.sess().trans_stats() {
         let mut instance_name = String::new();
@@ -598,18 +592,17 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
 
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
-    let fcx = FunctionContext::new(ccx, lldecl);
     let mir = ccx.tcx().item_mir(instance.def);
-    mir::trans_mir(&fcx, fn_ty, &mir, instance, &sig, abi);
+    mir::trans_mir(ccx, lldecl, fn_ty, &mir, instance, &sig, abi);
 }
 
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                  def_id: DefId,
                                  substs: &'tcx Substs<'tcx>,
                                  disr: Disr,
-                                 llfndecl: ValueRef) {
-    attributes::inline(llfndecl, attributes::InlineAttr::Hint);
-    attributes::set_frame_pointer_elimination(ccx, llfndecl);
+                                 llfn: ValueRef) {
+    attributes::inline(llfn, attributes::InlineAttr::Hint);
+    attributes::set_frame_pointer_elimination(ccx, llfn);
 
     let ctor_ty = ccx.tcx().item_type(def_id);
     let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
@@ -617,24 +610,29 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
-    let fcx = FunctionContext::new(ccx, llfndecl);
-    let bcx = fcx.get_entry_block();
+    let bcx = Builder::new_block(ccx, llfn, "entry-block");
     if !fn_ty.ret.is_ignore() {
         // But if there are no nested returns, we skip the indirection
         // and have a single retslot
         let dest = if fn_ty.ret.is_indirect() {
-            get_param(fcx.llfn, 0)
+            get_param(llfn, 0)
         } else {
             // We create an alloca to hold a pointer of type `ret.original_ty`
             // which will hold the pointer to the right alloca which has the
             // final ret value
-            fcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
+            bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
+        };
+        // Can return unsized value
+        let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output());
+        dest_val.ty = LvalueTy::Downcast {
+            adt_def: sig.output().ty_adt_def().unwrap(),
+            substs: substs,
+            variant_index: disr.0 as usize,
         };
-        let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
         let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
         let mut arg_idx = 0;
         for (i, arg_ty) in sig.inputs().iter().enumerate() {
-            let lldestptr = adt::trans_field_ptr(&bcx, sig.output(), dest_val, Disr::from(disr), i);
+            let lldestptr = dest_val.trans_field_ptr(&bcx, i);
             let arg = &fn_ty.args[arg_idx];
             arg_idx += 1;
             if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
@@ -761,12 +759,7 @@ fn create_entry_fn(ccx: &CrateContext,
         // `main` should respect same config for frame pointer elimination as rest of code
         attributes::set_frame_pointer_elimination(ccx, llfn);
 
-        let llbb = unsafe {
-            let name = CString::new("top").unwrap();
-            llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, name.as_ptr())
-        };
-        let bld = Builder::with_ccx(ccx);
-        bld.position_at_end(llbb);
+        let bld = Builder::new_block(ccx, llfn, "top");
 
         debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx, &bld);
 
index 136d1aad31a03965077995779028848e8b3ae033..cf7f3e9501d1a6e677a2576eac5e93681c4f84f4 100644 (file)
 use type_::Type;
 use value::Value;
 use libc::{c_uint, c_char};
+use rustc::ty::{Ty, TyCtxt, TypeFoldable};
+use rustc::session::Session;
+use type_of;
 
 use std::borrow::Cow;
 use std::ffi::CString;
 use std::ptr;
 use syntax_pos::Span;
 
+// All Builders must have an llfn associated with them
+#[must_use]
 pub struct Builder<'a, 'tcx: 'a> {
     pub llbuilder: BuilderRef,
     pub ccx: &'a CrateContext<'a, 'tcx>,
@@ -46,6 +51,20 @@ fn noname() -> *const c_char {
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
+    pub fn new_block<'b>(ccx: &'a CrateContext<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self {
+        let builder = Builder::with_ccx(ccx);
+        let llbb = unsafe {
+            let name = CString::new(name).unwrap();
+            llvm::LLVMAppendBasicBlockInContext(
+                ccx.llcx(),
+                llfn,
+                name.as_ptr()
+            )
+        };
+        builder.position_at_end(llbb);
+        builder
+    }
+
     pub fn with_ccx(ccx: &'a CrateContext<'a, 'tcx>) -> Self {
         // Create a fresh builder from the crate context.
         let llbuilder = unsafe {
@@ -57,6 +76,30 @@ pub fn with_ccx(ccx: &'a CrateContext<'a, 'tcx>) -> Self {
         }
     }
 
+    pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'tcx> {
+        Builder::new_block(self.ccx, self.llfn(), name)
+    }
+
+    pub fn sess(&self) -> &Session {
+        self.ccx.sess()
+    }
+
+    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.ccx.tcx()
+    }
+
+    pub fn llfn(&self) -> ValueRef {
+        unsafe {
+            llvm::LLVMGetBasicBlockParent(self.llbb())
+        }
+    }
+
+    pub fn llbb(&self) -> BasicBlockRef {
+        unsafe {
+            llvm::LLVMGetInsertBlock(self.llbuilder)
+        }
+    }
+
     fn count_insn(&self, category: &str) {
         if self.ccx.sess().trans_stats() {
             self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1);
@@ -435,6 +478,19 @@ pub fn not(&self, v: ValueRef) -> ValueRef {
         }
     }
 
+    pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+        let builder = Builder::with_ccx(self.ccx);
+        builder.position_at_start(unsafe {
+            llvm::LLVMGetFirstBasicBlock(self.llfn())
+        });
+        builder.dynamic_alloca(ty, name)
+    }
+
+    pub fn alloca_ty(&self, ty: Ty<'tcx>, name: &str) -> ValueRef {
+        assert!(!ty.has_param_types());
+        self.alloca(type_of::type_of(self.ccx, ty), name)
+    }
+
     pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
         self.count_insn("alloca");
         unsafe {
@@ -512,13 +568,17 @@ pub fn load_nonnull(&self, ptr: ValueRef) -> ValueRef {
         value
     }
 
-    pub fn store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
+    pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Option<u32>) -> ValueRef {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         assert!(!self.llbuilder.is_null());
         self.count_insn("store");
         let ptr = self.check_store(val, ptr);
         unsafe {
-            llvm::LLVMBuildStore(self.llbuilder, val, ptr)
+            let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
+            if let Some(align) = align {
+                llvm::LLVMSetAlignment(store, align as c_uint);
+            }
+            store
         }
     }
 
index 1abe25ea6073e6579dbb0e464076b04f896430d3..257d6c01e4a653fda7d79997cfd243b7b32bb620 100644 (file)
 use abi::{Abi, FnType};
 use attributes;
 use base;
-use base::*;
-use common::{
-    self, CrateContext, FunctionContext, SharedCrateContext
-};
-use adt::MaybeSizedValue;
+use builder::Builder;
+use common::{self, CrateContext, SharedCrateContext};
+use cleanup::CleanupScope;
+use mir::lvalue::LvalueRef;
 use consts;
 use declare;
 use value::Value;
@@ -330,8 +329,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     attributes::set_frame_pointer_elimination(ccx, lloncefn);
 
     let orig_fn_ty = fn_ty;
-    let fcx = FunctionContext::new(ccx, lloncefn);
-    let mut bcx = fcx.get_entry_block();
+    let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block");
 
     let callee = Callee {
         data: Fn(llreffn),
@@ -340,7 +338,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // the first argument (`self`) will be the (by value) closure env.
 
-    let mut llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(lloncefn);
     let fn_ret = callee.ty.fn_ret();
     let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
     let self_idx = fn_ty.ret.is_indirect() as usize;
@@ -348,7 +346,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let llenv = if env_arg.is_indirect() {
         llargs[self_idx]
     } else {
-        let scratch = alloc_ty(&bcx, closure_ty, "self");
+        let scratch = bcx.alloca_ty(closure_ty, "self");
         let mut llarg_idx = self_idx;
         env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch);
         scratch
@@ -365,12 +363,14 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Call the by-ref closure body with `self` in a cleanup scope,
     // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = fcx.schedule_drop_mem(MaybeSizedValue::sized(llenv), closure_ty);
+    let self_scope = CleanupScope::schedule_drop_mem(
+        &bcx, LvalueRef::new_sized_ty(llenv, closure_ty)
+    );
 
     let llfn = callee.reify(bcx.ccx);
     let llret;
     if let Some(landing_pad) = self_scope.landing_pad {
-        let normal_bcx = bcx.fcx().build_new_block("normal-return");
+        let normal_bcx = bcx.build_sibling_block("normal-return");
         llret = bcx.invoke(llfn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
         bcx = normal_bcx;
     } else {
@@ -489,10 +489,9 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
     //
-    let fcx = FunctionContext::new(ccx, llfn);
-    let bcx = fcx.get_entry_block();
+    let bcx = Builder::new_block(ccx, llfn, "entry-block");
 
-    let mut llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(llfn);
 
     let self_arg = llargs.remove(fn_ty.ret.is_indirect() as usize);
     let llfnpointer = llfnpointer.unwrap_or_else(|| {
index 4e59ea3f6c5ed71664a5bc9078684291ee03fdf7..5d89a67d3fd80890029273f3c6b01bfc64c406ac 100644 (file)
 
 use llvm::BasicBlockRef;
 use base;
-use adt::MaybeSizedValue;
-use common::{BlockAndBuilder, FunctionContext, Funclet};
+use mir::lvalue::LvalueRef;
+use rustc::mir::tcx::LvalueTy;
+use builder::Builder;
+use common::Funclet;
 use glue;
 use type_::Type;
-use rustc::ty::Ty;
 
 pub struct CleanupScope<'tcx> {
     // Cleanup to run upon scope exit.
@@ -36,14 +37,13 @@ pub struct CleanupScope<'tcx> {
 
 #[derive(Copy, Clone)]
 pub struct DropValue<'tcx> {
-    val: MaybeSizedValue,
-    ty: Ty<'tcx>,
+    val: LvalueRef<'tcx>,
     skip_dtor: bool,
 }
 
 impl<'tcx> DropValue<'tcx> {
-    fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &BlockAndBuilder<'a, 'tcx>) {
-        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
+    fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &Builder<'a, 'tcx>) {
+        glue::call_drop_glue(bcx, self.val, self.skip_dtor, funclet)
     }
 
     /// Creates a landing pad for the top scope. The landing pad will perform all cleanups necessary
@@ -52,13 +52,13 @@ fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &BlockAndBuilder<'a, 'tcx
     ///     landing_pad -> ... cleanups ... -> [resume]
     ///
     /// This should only be called once per function, as it creates an alloca for the landingpad.
-    fn get_landing_pad<'a>(&self, fcx: &FunctionContext<'a, 'tcx>) -> BasicBlockRef {
+    fn get_landing_pad<'a>(&self, bcx: &Builder<'a, 'tcx>) -> BasicBlockRef {
         debug!("get_landing_pad");
-        let bcx = fcx.build_new_block("cleanup_unwind");
+        let bcx = bcx.build_sibling_block("cleanup_unwind");
         let llpersonality = bcx.ccx.eh_personality();
         bcx.set_personality_fn(llpersonality);
 
-        if base::wants_msvc_seh(fcx.ccx.sess()) {
+        if base::wants_msvc_seh(bcx.sess()) {
             let pad = bcx.cleanup_pad(None, &[]);
             let funclet = Some(Funclet::new(pad));
             self.trans(funclet.as_ref(), &bcx);
@@ -68,10 +68,10 @@ fn get_landing_pad<'a>(&self, fcx: &FunctionContext<'a, 'tcx>) -> BasicBlockRef
             // The landing pad return type (the type being propagated). Not sure
             // what this represents but it's determined by the personality
             // function and this is what the EH proposal example uses.
-            let llretty = Type::struct_(fcx.ccx, &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)], false);
+            let llretty = Type::struct_(bcx.ccx, &[Type::i8p(bcx.ccx), Type::i32(bcx.ccx)], false);
 
             // The only landing pad clause will be 'cleanup'
-            let llretval = bcx.landing_pad(llretty, llpersonality, 1, bcx.fcx().llfn);
+            let llretval = bcx.landing_pad(llretty, llpersonality, 1, bcx.llfn());
 
             // The landing pad block is a cleanup
             bcx.set_cleanup(llretval);
@@ -92,17 +92,23 @@ fn get_landing_pad<'a>(&self, fcx: &FunctionContext<'a, 'tcx>) -> BasicBlockRef
     }
 }
 
-impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
+impl<'a, 'tcx> CleanupScope<'tcx> {
     /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
-    pub fn schedule_drop_mem(&self, val: MaybeSizedValue, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
-        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
+    pub fn schedule_drop_mem(
+        bcx: &Builder<'a, 'tcx>, val: LvalueRef<'tcx>
+    ) -> CleanupScope<'tcx> {
+        if let LvalueTy::Downcast { .. } = val.ty {
+            bug!("Cannot drop downcast ty yet");
+        }
+        if !bcx.ccx.shared().type_needs_drop(val.ty.to_ty(bcx.tcx())) {
+            return CleanupScope::noop();
+        }
         let drop = DropValue {
             val: val,
-            ty: ty,
             skip_dtor: false,
         };
 
-        CleanupScope::new(self, drop)
+        CleanupScope::new(bcx, drop)
     }
 
     /// Issue #23611: Schedules a (deep) drop of the contents of
@@ -110,28 +116,31 @@ pub fn schedule_drop_mem(&self, val: MaybeSizedValue, ty: Ty<'tcx>) -> CleanupSc
     /// `ty`. The scheduled code handles extracting the discriminant
     /// and dropping the contents associated with that variant
     /// *without* executing any associated drop implementation.
-    pub fn schedule_drop_adt_contents(&self, val: MaybeSizedValue, ty: Ty<'tcx>)
-        -> CleanupScope<'tcx> {
+    pub fn schedule_drop_adt_contents(
+        bcx: &Builder<'a, 'tcx>, val: LvalueRef<'tcx>
+    ) -> CleanupScope<'tcx> {
+        if let LvalueTy::Downcast { .. } = val.ty {
+            bug!("Cannot drop downcast ty yet");
+        }
         // `if` below could be "!contents_needs_drop"; skipping drop
         // is just an optimization, so sound to be conservative.
-        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
+        if !bcx.ccx.shared().type_needs_drop(val.ty.to_ty(bcx.tcx())) {
+            return CleanupScope::noop();
+        }
 
         let drop = DropValue {
             val: val,
-            ty: ty,
             skip_dtor: true,
         };
 
-        CleanupScope::new(self, drop)
+        CleanupScope::new(bcx, drop)
     }
-}
 
-impl<'tcx> CleanupScope<'tcx> {
-    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
+    fn new(bcx: &Builder<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
         CleanupScope {
             cleanup: Some(drop_val),
-            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
-                Some(drop_val.get_landing_pad(fcx))
+            landing_pad: if !bcx.sess().no_landing_pads() {
+                Some(drop_val.get_landing_pad(bcx))
             } else {
                 None
             },
@@ -145,7 +154,7 @@ pub fn noop() -> CleanupScope<'tcx> {
         }
     }
 
-    pub fn trans<'a>(self, bcx: &'a BlockAndBuilder<'a, 'tcx>) {
+    pub fn trans(self, bcx: &'a Builder<'a, 'tcx>) {
         if let Some(cleanup) = self.cleanup {
             cleanup.trans(None, &bcx);
         }
index 7e7bd15dc6e5ad6730fd5e96a4a6b5a16bd46c81..13163518f941ec710875127a62f3a94b3fca34e7 100644 (file)
 
 //! Code that is useful in various trans modules.
 
-use session::Session;
 use llvm;
-use llvm::{ValueRef, BasicBlockRef, ContextRef, TypeKind};
+use llvm::{ValueRef, ContextRef, TypeKind};
 use llvm::{True, False, Bool, OperandBundleDef};
-use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::util::common::MemoizationMap;
 use libc::{c_uint, c_char};
 use std::borrow::Cow;
 use std::iter;
-use std::ops::Deref;
-use std::ffi::CString;
 
 use syntax::ast;
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::InternedString;
 use syntax_pos::Span;
 
 use rustc_i128::u128;
@@ -172,191 +168,6 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
 *
 */
 
-use Disr;
-
-/// The concrete version of ty::FieldDef. The name is the field index if
-/// the field is numeric.
-pub struct Field<'tcx>(pub ast::Name, pub Ty<'tcx>);
-
-/// The concrete version of ty::VariantDef
-pub struct VariantInfo<'tcx> {
-    pub discr: Disr,
-    pub fields: Vec<Field<'tcx>>
-}
-
-impl<'a, 'tcx> VariantInfo<'tcx> {
-    pub fn from_ty(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                   ty: Ty<'tcx>,
-                   opt_def: Option<Def>)
-                   -> Self
-    {
-        match ty.sty {
-            ty::TyAdt(adt, substs) => {
-                let variant = match opt_def {
-                    None => adt.struct_variant(),
-                    Some(def) => adt.variant_of_def(def)
-                };
-
-                VariantInfo {
-                    discr: Disr::from(variant.disr_val),
-                    fields: variant.fields.iter().map(|f| {
-                        Field(f.name, monomorphize::field_ty(tcx, substs, f))
-                    }).collect()
-                }
-            }
-
-            ty::TyTuple(ref v) => {
-                VariantInfo {
-                    discr: Disr(0),
-                    fields: v.iter().enumerate().map(|(i, &t)| {
-                        Field(Symbol::intern(&i.to_string()), t)
-                    }).collect()
-                }
-            }
-
-            _ => {
-                bug!("cannot get field types from the type {:?}", ty);
-            }
-        }
-    }
-}
-
-// Function context. Every LLVM function we create will have one of these.
-pub struct FunctionContext<'a, 'tcx: 'a> {
-    // The ValueRef returned from a call to llvm::LLVMAddFunction; the
-    // address of the first instruction in the sequence of
-    // instructions for this function that will go in the .text
-    // section of the executable we're generating.
-    pub llfn: ValueRef,
-
-    // A marker for the place where we want to insert the function's static
-    // allocas, so that LLVM will coalesce them into a single alloca call.
-    alloca_insert_pt: Option<ValueRef>,
-
-    // This function's enclosing crate context.
-    pub ccx: &'a CrateContext<'a, 'tcx>,
-
-    alloca_builder: Builder<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
-    /// Create a function context for the given function.
-    /// Call FunctionContext::get_entry_block for the first entry block.
-    pub fn new(ccx: &'a CrateContext<'a, 'tcx>, llfndecl: ValueRef) -> FunctionContext<'a, 'tcx> {
-        let mut fcx = FunctionContext {
-            llfn: llfndecl,
-            alloca_insert_pt: None,
-            ccx: ccx,
-            alloca_builder: Builder::with_ccx(ccx),
-        };
-
-        let val = {
-            let entry_bcx = fcx.build_new_block("entry-block");
-            let val = entry_bcx.load(C_null(Type::i8p(ccx)));
-            fcx.alloca_builder.position_at_start(entry_bcx.llbb());
-            val
-        };
-
-        // Use a dummy instruction as the insertion point for all allocas.
-        // This is later removed in the drop of FunctionContext.
-        fcx.alloca_insert_pt = Some(val);
-
-        fcx
-    }
-
-    pub fn get_entry_block(&'a self) -> BlockAndBuilder<'a, 'tcx> {
-        BlockAndBuilder::new(unsafe {
-            llvm::LLVMGetFirstBasicBlock(self.llfn)
-        }, self)
-    }
-
-    pub fn new_block(&'a self, name: &str) -> BasicBlockRef {
-        unsafe {
-            let name = CString::new(name).unwrap();
-            llvm::LLVMAppendBasicBlockInContext(
-                self.ccx.llcx(),
-                self.llfn,
-                name.as_ptr()
-            )
-        }
-    }
-
-    pub fn build_new_block(&'a self, name: &str) -> BlockAndBuilder<'a, 'tcx> {
-        BlockAndBuilder::new(self.new_block(name), self)
-    }
-
-    pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
-        self.alloca_builder.dynamic_alloca(ty, name)
-    }
-}
-
-impl<'a, 'tcx> Drop for FunctionContext<'a, 'tcx> {
-    fn drop(&mut self) {
-        unsafe {
-            llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.unwrap());
-        }
-    }
-}
-
-#[must_use]
-pub struct BlockAndBuilder<'a, 'tcx: 'a> {
-    // The BasicBlockRef returned from a call to
-    // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
-    // block to the function pointed to by llfn.  We insert
-    // instructions into that block by way of this block context.
-    // The block pointing to this one in the function's digraph.
-    llbb: BasicBlockRef,
-
-    // The function context for the function to which this block is
-    // attached.
-    fcx: &'a FunctionContext<'a, 'tcx>,
-
-    builder: Builder<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> BlockAndBuilder<'a, 'tcx> {
-    pub fn new(llbb: BasicBlockRef, fcx: &'a FunctionContext<'a, 'tcx>) -> Self {
-        let builder = Builder::with_ccx(fcx.ccx);
-        // Set the builder's position to this block's end.
-        builder.position_at_end(llbb);
-        BlockAndBuilder {
-            llbb: llbb,
-            fcx: fcx,
-            builder: builder,
-        }
-    }
-
-    pub fn at_start<F, R>(&self, f: F) -> R
-        where F: FnOnce(&BlockAndBuilder<'a, 'tcx>) -> R
-    {
-        self.position_at_start(self.llbb);
-        let r = f(self);
-        self.position_at_end(self.llbb);
-        r
-    }
-
-    pub fn fcx(&self) -> &'a FunctionContext<'a, 'tcx> {
-        self.fcx
-    }
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.ccx.tcx()
-    }
-    pub fn sess(&self) -> &'a Session {
-        self.ccx.sess()
-    }
-
-    pub fn llbb(&self) -> BasicBlockRef {
-        self.llbb
-    }
-}
-
-impl<'a, 'tcx> Deref for BlockAndBuilder<'a, 'tcx> {
-    type Target = Builder<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        &self.builder
-    }
-}
-
 /// A structure representing an active landing pad for the duration of a basic
 /// block.
 ///
@@ -725,7 +536,7 @@ pub fn langcall(tcx: TyCtxt,
 // of Java. (See related discussion on #1877 and #10183.)
 
 pub fn build_unchecked_lshift<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     lhs: ValueRef,
     rhs: ValueRef
 ) -> ValueRef {
@@ -736,7 +547,7 @@ pub fn build_unchecked_lshift<'a, 'tcx>(
 }
 
 pub fn build_unchecked_rshift<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef
+    bcx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef
 ) -> ValueRef {
     let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
     // #1877, #10183: Ensure that input is always valid
@@ -749,13 +560,13 @@ pub fn build_unchecked_rshift<'a, 'tcx>(
     }
 }
 
-fn shift_mask_rhs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, rhs: ValueRef) -> ValueRef {
+fn shift_mask_rhs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef {
     let rhs_llty = val_ty(rhs);
     bcx.and(rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false))
 }
 
 pub fn shift_mask_val<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     llty: Type,
     mask_llty: Type,
     invert: bool
index f5a8eeacf38adba37051666d798402945cb92170..c6f8ba7b6dc78d79c5fdcb2f7955e086c24c1b27 100644 (file)
@@ -14,7 +14,7 @@
 
 use llvm;
 use llvm::debuginfo::{DIScope, DISubprogram};
-use common::{CrateContext, FunctionContext};
+use common::CrateContext;
 use rustc::mir::{Mir, VisibilityScope};
 
 use libc::c_uint;
@@ -44,7 +44,7 @@ pub fn is_valid(&self) -> bool {
 
 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
 /// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir, debug_context: &FunctionDebugContext)
+pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &FunctionDebugContext)
     -> IndexVec<VisibilityScope, MirDebugScope> {
     let null_scope = MirDebugScope {
         scope_metadata: ptr::null_mut(),
@@ -71,7 +71,7 @@ pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir, debug_context: &Funct
     // Instantiate all scopes.
     for idx in 0..mir.visibility_scopes.len() {
         let scope = VisibilityScope::new(idx);
-        make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
+        make_mir_scope(ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
     }
 
     scopes
index bcf5eb99200766c3b758e1154cb57ed705e75bcf..7a739071506dbe2f3b1c933d92dd4d4ef96f6b70 100644 (file)
@@ -45,7 +45,7 @@
 //!
 //! All private state used by the module is stored within either the
 //! CrateDebugContext struct (owned by the CrateContext) or the
-//! FunctionDebugContext (owned by the FunctionContext).
+//! FunctionDebugContext (owned by the MirContext).
 //!
 //! This file consists of three conceptual sections:
 //! 1. The public interface of the module
index b2d12c7e7d0f2a323130bdcefd4f74bdb2029b48..f6428465eda203dbdd03823df5bbb8bb418a4af8 100644 (file)
@@ -906,7 +906,7 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
 
             MemberDescription {
                 name: name,
-                llvm_type: type_of::type_of(cx, fty),
+                llvm_type: type_of::in_memory_type_of(cx, fty),
                 type_metadata: type_metadata(cx, fty, self.span),
                 offset: offset,
                 flags: DIFlags::FlagZero,
index 86099d241df686bec35b2594f87cb3ef78e990ab..9117f49cf3ea5b8aaa3ec3fc0a343df1e0113a81 100644 (file)
@@ -27,7 +27,8 @@
 use rustc::ty::subst::Substs;
 
 use abi::Abi;
-use common::{CrateContext, BlockAndBuilder};
+use common::CrateContext;
+use builder::Builder;
 use monomorphize::{self, Instance};
 use rustc::ty::{self, Ty};
 use rustc::mir;
@@ -423,7 +424,7 @@ fn get_containing_scope<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
     }
 }
 
-pub fn declare_local<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                dbg_context: &FunctionDebugContext,
                                variable_name: ast::Name,
                                variable_type: Ty<'tcx>,
index e02c8be19a2f477315c2e1cdf671ee205c7f6796..e99e26261a3a1017d366f2a4af32142c1e358866 100644 (file)
@@ -38,7 +38,7 @@ pub fn set_source_location(
     };
 
     let dbg_loc = if function_debug_context.source_locations_enabled.get() {
-        debug!("set_source_location: {}", builder.ccx.sess().codemap().span_to_string(span));
+        debug!("set_source_location: {}", builder.sess().codemap().span_to_string(span));
         let loc = span_start(builder.ccx, span);
         InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
     } else {
index 62141369caec1cf11a3644e8fef37e6d02ccbc06..4fe07c9b86abfa738fcd01b53b5a3c2f2a9cb3b5 100644 (file)
@@ -13,6 +13,7 @@
 // Code relating to drop glue.
 
 use std;
+use std::ptr;
 use std::iter;
 
 use llvm;
 use middle::lang_items::BoxFreeFnLangItem;
 use rustc::ty::subst::{Substs};
 use rustc::traits;
-use rustc::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc::ty::{self, layout, AdtDef, AdtKind, Ty, TypeFoldable};
 use rustc::ty::subst::Kind;
-use adt::{self, MaybeSizedValue};
+use rustc::mir::tcx::LvalueTy;
+use mir::lvalue::LvalueRef;
+use adt;
 use base::*;
 use callee::Callee;
+use cleanup::CleanupScope;
 use common::*;
 use machine::*;
 use monomorphize;
 use type_::Type;
 use value::Value;
 use Disr;
-use cleanup::CleanupScope;
+use builder::Builder;
 
 use syntax_pos::DUMMY_SP;
 
-pub fn trans_exchange_free_ty<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
-    ptr: MaybeSizedValue,
-    content_ty: Ty<'tcx>
-) {
+pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<'tcx>) {
+    let content_ty = ptr.ty.to_ty(bcx.tcx());
     let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem);
     let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty)));
     let callee = Callee::def(bcx.ccx, def_id, substs);
@@ -50,7 +51,7 @@ pub fn trans_exchange_free_ty<'a, 'tcx>(
     let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
 
     let llret = bcx.call(callee.reify(bcx.ccx),
-        &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize], None);
+        &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize], None);
     fn_ty.apply_attrs_callsite(llret);
 }
 
@@ -93,17 +94,17 @@ pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'t
     }
 }
 
-fn drop_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, args: MaybeSizedValue, t: Ty<'tcx>) {
-    call_drop_glue(bcx, args, t, false, None)
+fn drop_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, args: LvalueRef<'tcx>) {
+    call_drop_glue(bcx, args, false, None)
 }
 
 pub fn call_drop_glue<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
-    mut args: MaybeSizedValue,
-    t: Ty<'tcx>,
+    bcx: &Builder<'a, 'tcx>,
+    mut args: LvalueRef<'tcx>,
     skip_dtor: bool,
     funclet: Option<&'a Funclet>,
 ) {
+    let t = args.ty.to_ty(bcx.tcx());
     // NB: v is an *alias* of type t here, not a direct value.
     debug!("call_drop_glue(t={:?}, skip_dtor={})", t, skip_dtor);
     if bcx.ccx.shared().type_needs_drop(t) {
@@ -116,11 +117,11 @@ pub fn call_drop_glue<'a, 'tcx>(
         let glue = get_drop_glue_core(ccx, g);
         let glue_type = get_drop_glue_type(ccx.shared(), t);
         if glue_type != t {
-            args.value = bcx.pointercast(args.value, type_of(ccx, glue_type).ptr_to());
+            args.llval = bcx.pointercast(args.llval, type_of(ccx, glue_type).ptr_to());
         }
 
         // No drop-hint ==> call standard drop glue
-        bcx.call(glue, &[args.value, args.meta][..1 + args.has_meta() as usize],
+        bcx.call(glue, &[args.llval, args.llextra][..1 + args.has_extra() as usize],
             funclet.map(|b| b.bundle()));
     }
 }
@@ -173,8 +174,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
     assert_eq!(g.ty(), get_drop_glue_type(ccx.shared(), g.ty()));
     let (llfn, _) = ccx.drop_glues().borrow().get(&g).unwrap().clone();
 
-    let fcx = FunctionContext::new(ccx, llfn);
-    let mut bcx = fcx.get_entry_block();
+    let mut bcx = Builder::new_block(ccx, llfn, "entry-block");
 
     ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
     // All glue functions take values passed *by alias*; this is a
@@ -194,9 +194,9 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
 
     let value = get_param(llfn, 0);
     let ptr = if ccx.shared().type_is_sized(t) {
-        MaybeSizedValue::sized(value)
+        LvalueRef::new_sized_ty(value, t)
     } else {
-        MaybeSizedValue::unsized_(value, get_param(llfn, 1))
+        LvalueRef::new_unsized_ty(value, get_param(llfn, 1), t)
     };
 
     let skip_dtor = match g {
@@ -211,14 +211,14 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             // a safe-guard, assert TyBox not used with TyContents.
             assert!(!skip_dtor);
             let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) {
-                let llbox = bcx.load(get_dataptr(&bcx, ptr.value));
-                let info = bcx.load(get_meta(&bcx, ptr.value));
-                MaybeSizedValue::unsized_(llbox, info)
+                let llbox = bcx.load(get_dataptr(&bcx, ptr.llval));
+                let info = bcx.load(get_meta(&bcx, ptr.llval));
+                LvalueRef::new_unsized_ty(llbox, info, content_ty)
             } else {
-                MaybeSizedValue::sized(bcx.load(ptr.value))
+                LvalueRef::new_sized_ty(bcx.load(ptr.llval), content_ty)
             };
-            drop_ty(&bcx, ptr, content_ty);
-            trans_exchange_free_ty(&bcx, ptr, content_ty);
+            drop_ty(&bcx, ptr);
+            trans_exchange_free_ty(&bcx, ptr);
             bcx
         }
         ty::TyDynamic(..) => {
@@ -226,8 +226,8 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             // versus without calling Drop::drop. Assert caller is
             // okay with always calling the Drop impl, if any.
             assert!(!skip_dtor);
-            let dtor = bcx.load(ptr.meta);
-            bcx.call(dtor, &[ptr.value], None);
+            let dtor = bcx.load(ptr.llextra);
+            bcx.call(dtor, &[ptr.llval], None);
             bcx
         }
         ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => {
@@ -245,7 +245,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             // Issue #23611: schedule cleanup of contents, re-inspecting the
             // discriminant (if any) in case of variant swap in drop code.
             let contents_scope = if !shallow_drop {
-                bcx.fcx().schedule_drop_adt_contents(ptr, t)
+                CleanupScope::schedule_drop_adt_contents(&bcx, ptr)
             } else {
                 CleanupScope::noop()
             };
@@ -262,9 +262,9 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
             let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
             let llret;
-            let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
+            let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize];
             if let Some(landing_pad) = contents_scope.landing_pad {
-                let normal_bcx = bcx.fcx().build_new_block("normal-return");
+                let normal_bcx = bcx.build_sibling_block("normal-return");
                 llret = bcx.invoke(callee.reify(ccx), args, normal_bcx.llbb(), landing_pad, None);
                 bcx = normal_bcx;
             } else {
@@ -279,7 +279,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
         }
         _ => {
             if bcx.ccx.shared().type_needs_drop(t) {
-                drop_structural_ty(bcx, ptr, t)
+                drop_structural_ty(bcx, ptr)
             } else {
                 bcx
             }
@@ -288,8 +288,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
     bcx.ret_void();
 }
 
-pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
-                                       t: Ty<'tcx>, info: ValueRef)
+pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
                                        -> (ValueRef, ValueRef) {
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, Value(info));
@@ -397,60 +396,64 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
 }
 
 // Iterates through the elements of a structural type, dropping them.
-fn drop_structural_ty<'a, 'tcx>(cx: BlockAndBuilder<'a, 'tcx>,
-                                ptr: MaybeSizedValue,
-                                t: Ty<'tcx>)
-                                -> BlockAndBuilder<'a, 'tcx> {
-    fn iter_variant<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
-                              t: Ty<'tcx>,
-                              av: adt::MaybeSizedValue,
-                              variant: &'tcx ty::VariantDef,
-                              substs: &Substs<'tcx>) {
+fn drop_structural_ty<'a, 'tcx>(
+    cx: Builder<'a, 'tcx>,
+    mut ptr: LvalueRef<'tcx>
+) -> Builder<'a, 'tcx> {
+    fn iter_variant_fields<'a, 'tcx>(
+        cx: &'a Builder<'a, 'tcx>,
+        av: LvalueRef<'tcx>,
+        adt_def: &'tcx AdtDef,
+        variant_index: usize,
+        substs: &'tcx Substs<'tcx>
+    ) {
+        let variant = &adt_def.variants[variant_index];
         let tcx = cx.tcx();
         for (i, field) in variant.fields.iter().enumerate() {
             let arg = monomorphize::field_ty(tcx, substs, field);
-            let field_ptr = adt::trans_field_ptr(&cx, t, av, Disr::from(variant.disr_val), i);
-            drop_ty(&cx, MaybeSizedValue::sized(field_ptr), arg);
+            let field_ptr = av.trans_field_ptr(&cx, i);
+            drop_ty(&cx, LvalueRef::new_sized_ty(field_ptr, arg));
         }
     }
 
     let mut cx = cx;
+    let t = ptr.ty.to_ty(cx.tcx());
     match t.sty {
         ty::TyClosure(def_id, substs) => {
             for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() {
-                let llupvar = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
-                drop_ty(&cx, MaybeSizedValue::sized(llupvar), upvar_ty);
+                let llupvar = ptr.trans_field_ptr(&cx, i);
+                drop_ty(&cx, LvalueRef::new_sized_ty(llupvar, upvar_ty));
             }
         }
         ty::TyArray(_, n) => {
-            let base = get_dataptr(&cx, ptr.value);
+            let base = get_dataptr(&cx, ptr.llval);
             let len = C_uint(cx.ccx, n);
             let unit_ty = t.sequence_element_type(cx.tcx());
             cx = tvec::slice_for_each(&cx, base, unit_ty, len,
-                |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
+                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(cx.tcx());
-            cx = tvec::slice_for_each(&cx, ptr.value, unit_ty, ptr.meta,
-                |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
+            cx = tvec::slice_for_each(&cx, ptr.llval, unit_ty, ptr.llextra,
+                |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
         }
         ty::TyTuple(ref args) => {
             for (i, arg) in args.iter().enumerate() {
-                let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
-                drop_ty(&cx, MaybeSizedValue::sized(llfld_a), *arg);
+                let llfld_a = ptr.trans_field_ptr(&cx, i);
+                drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg));
             }
         }
         ty::TyAdt(adt, substs) => match adt.adt_kind() {
             AdtKind::Struct => {
-                let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None);
-                for (i, &Field(_, field_ty)) in fields.iter().enumerate() {
-                    let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr::from(discr), i);
-                    let ptr = if cx.ccx.shared().type_is_sized(field_ty) {
-                        MaybeSizedValue::sized(llfld_a)
-                    } else {
-                        MaybeSizedValue::unsized_(llfld_a, ptr.meta)
-                    };
-                    drop_ty(&cx, ptr, field_ty);
+                for (i, field) in adt.variants[0].fields.iter().enumerate() {
+                    let field_ty = monomorphize::field_ty(cx.tcx(), substs, field);
+                    let mut field_ptr = ptr.clone();
+                    field_ptr.llval = ptr.trans_field_ptr(&cx, i);
+                    field_ptr.ty = LvalueTy::from_ty(field_ty);
+                    if cx.ccx.shared().type_is_sized(field_ty) {
+                        field_ptr.llextra = ptr::null_mut();
+                    }
+                    drop_ty(&cx, field_ptr);
                 }
             }
             AdtKind::Union => {
@@ -462,16 +465,29 @@ fn iter_variant<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
                 // NB: we must hit the discriminant first so that structural
                 // comparison know not to proceed when the discriminants differ.
 
-                match adt::trans_switch(&cx, t, ptr.value, false) {
-                    (adt::BranchKind::Single, None) => {
+                // Obtain a representation of the discriminant sufficient to translate
+                // destructuring; this may or may not involve the actual discriminant.
+                let l = cx.ccx.layout_of(t);
+                match *l {
+                    layout::Univariant { .. } |
+                    layout::UntaggedUnion { .. } => {
                         if n_variants != 0 {
                             assert!(n_variants == 1);
-                            iter_variant(&cx, t, ptr, &adt.variants[0], substs);
+                            ptr.ty = LvalueTy::Downcast {
+                                adt_def: adt,
+                                substs: substs,
+                                variant_index: 0,
+                            };
+                            iter_variant_fields(&cx, ptr, &adt, 0, substs);
                         }
                     }
-                    (adt::BranchKind::Switch, Some(lldiscrim_a)) => {
+                    layout::CEnum { .. } |
+                    layout::General { .. } |
+                    layout::RawNullablePointer { .. } |
+                    layout::StructWrappedNullablePointer { .. } => {
+                        let lldiscrim_a = adt::trans_get_discr(&cx, t, ptr.llval, None, false);
                         let tcx = cx.tcx();
-                        drop_ty(&cx, MaybeSizedValue::sized(lldiscrim_a), tcx.types.isize);
+                        drop_ty(&cx, LvalueRef::new_sized_ty(lldiscrim_a, tcx.types.isize));
 
                         // Create a fall-through basic block for the "else" case of
                         // the switch instruction we're about to generate. Note that
@@ -486,23 +502,28 @@ fn iter_variant<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
                         // from the outer function, and any other use case will only
                         // call this for an already-valid enum in which case the `ret
                         // void` will never be hit.
-                        let ret_void_cx = cx.fcx().build_new_block("enum-iter-ret-void");
+                        let ret_void_cx = cx.build_sibling_block("enum-iter-ret-void");
                         ret_void_cx.ret_void();
                         let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
-                        let next_cx = cx.fcx().build_new_block("enum-iter-next");
+                        let next_cx = cx.build_sibling_block("enum-iter-next");
 
-                        for variant in &adt.variants {
+                        for (i, variant) in adt.variants.iter().enumerate() {
                             let variant_cx_name = format!("enum-iter-variant-{}",
                                 &variant.disr_val.to_string());
-                            let variant_cx = cx.fcx().build_new_block(&variant_cx_name);
+                            let variant_cx = cx.build_sibling_block(&variant_cx_name);
                             let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
                             variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
-                            iter_variant(&variant_cx, t, ptr, variant, substs);
+                            ptr.ty = LvalueTy::Downcast {
+                                adt_def: adt,
+                                substs: substs,
+                                variant_index: i,
+                            };
+                            iter_variant_fields(&variant_cx, ptr, &adt, i, substs);
                             variant_cx.br(next_cx.llbb());
                         }
                         cx = next_cx;
                     }
-                    _ => cx.ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"),
+                    _ => bug!("{} is not an enum.", t),
                 }
             }
         },
index c4129b346e409b4dca0d2a4762ae2035a2e5ca25..842a21e98db46f12686db159bd8d27cb9421afcd 100644 (file)
@@ -16,6 +16,7 @@
 use llvm::{ValueRef};
 use abi::{Abi, FnType};
 use adt;
+use mir::lvalue::LvalueRef;
 use base::*;
 use common::*;
 use declare;
 use machine;
 use type_::Type;
 use rustc::ty::{self, Ty};
-use Disr;
 use rustc::hir;
 use syntax::ast;
 use syntax::symbol::Symbol;
+use builder::Builder;
 
 use rustc::session::Session;
 use syntax_pos::Span;
@@ -87,14 +88,14 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
 /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
 /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
 /// add them to librustc_trans/trans/context.rs
-pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                       callee_ty: Ty<'tcx>,
                                       fn_ty: &FnType,
                                       llargs: &[ValueRef],
                                       llresult: ValueRef,
                                       span: Span) {
     let ccx = bcx.ccx;
-    let tcx = bcx.tcx();
+    let tcx = ccx.tcx();
 
     let (def_id, substs, fty) = match callee_ty.sty {
         ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
@@ -125,7 +126,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
             bcx.call(expect, &[llargs[0], C_bool(ccx, false)], None)
         }
         "try" => {
-            try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult);
+            try_intrinsic(bcx, ccx, llargs[0], llargs[1], llargs[2], llresult);
             C_nil(ccx)
         }
         "breakpoint" => {
@@ -290,8 +291,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                             let val = bcx.call(llfn, &[llargs[0], llargs[1]], None);
                             let result = bcx.extract_value(val, 0);
                             let overflow = bcx.zext(bcx.extract_value(val, 1), Type::bool(ccx));
-                            bcx.store(result, bcx.struct_gep(llresult, 0));
-                            bcx.store(overflow, bcx.struct_gep(llresult, 1));
+                            bcx.store(result, bcx.struct_gep(llresult, 0), None);
+                            bcx.store(overflow, bcx.struct_gep(llresult, 1), None);
 
                             C_nil(bcx.ccx)
                         },
@@ -409,8 +410,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                             failorder, weak);
                         let result = bcx.extract_value(val, 0);
                         let success = bcx.zext(bcx.extract_value(val, 1), Type::bool(bcx.ccx));
-                        bcx.store(result, bcx.struct_gep(llresult, 0));
-                        bcx.store(success, bcx.struct_gep(llresult, 1));
+                        bcx.store(result, bcx.struct_gep(llresult, 0), None);
+                        bcx.store(success, bcx.struct_gep(llresult, 1), None);
                     } else {
                         invalid_monomorphization(sty);
                     }
@@ -533,7 +534,7 @@ fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type,
             // qux` to be converted into `foo, bar, baz, qux`, integer
             // arguments to be truncated as needed and pointers to be
             // cast.
-            fn modify_as_needed<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+            fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                           t: &intrinsics::Type,
                                           arg_type: Ty<'tcx>,
                                           llarg: ValueRef)
@@ -548,12 +549,8 @@ fn modify_as_needed<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                         // destructors, and the contents are SIMD
                         // etc.
                         assert!(!bcx.ccx.shared().type_needs_drop(arg_type));
-                        let arg = adt::MaybeSizedValue::sized(llarg);
-                        (0..contents.len())
-                            .map(|i| {
-                                bcx.load(adt::trans_field_ptr(bcx, arg_type, arg, Disr(0), i))
-                            })
-                            .collect()
+                        let arg = LvalueRef::new_sized_ty(llarg, arg_type);
+                        (0..contents.len()).map(|i| bcx.load(arg.trans_field_ptr(bcx, i))).collect()
                     }
                     intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => {
                         let llvm_elem = one(ty_to_type(bcx.ccx, llvm_elem, &mut false));
@@ -615,7 +612,7 @@ fn modify_as_needed<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
 
                     for i in 0..elems.len() {
                         let val = bcx.extract_value(val, i);
-                        bcx.store(val, bcx.struct_gep(llresult, i));
+                        bcx.store(val, bcx.struct_gep(llresult, i), None);
                     }
                     C_nil(ccx)
                 }
@@ -627,17 +624,14 @@ fn modify_as_needed<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
     if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
         if let Some(ty) = fn_ty.ret.cast {
             let ptr = bcx.pointercast(llresult, ty.ptr_to());
-            let store = bcx.store(llval, ptr);
-            unsafe {
-                llvm::LLVMSetAlignment(store, type_of::align_of(ccx, ret_ty));
-            }
+            bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
         } else {
             store_ty(bcx, llval, llresult, ret_ty);
         }
     }
 }
 
-fn copy_intrinsic<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                             allow_overlap: bool,
                             volatile: bool,
                             tp_ty: Ty<'tcx>,
@@ -673,7 +667,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
 }
 
 fn memset_intrinsic<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     volatile: bool,
     ty: Ty<'tcx>,
     dst: ValueRef,
@@ -689,7 +683,8 @@ fn memset_intrinsic<'a, 'tcx>(
 }
 
 fn try_intrinsic<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
+    ccx: &CrateContext,
     func: ValueRef,
     data: ValueRef,
     local_ptr: ValueRef,
@@ -697,11 +692,11 @@ fn try_intrinsic<'a, 'tcx>(
 ) {
     if bcx.sess().no_landing_pads() {
         bcx.call(func, &[data], None);
-        bcx.store(C_null(Type::i8p(&bcx.ccx)), dest);
+        bcx.store(C_null(Type::i8p(&bcx.ccx)), dest, None);
     } else if wants_msvc_seh(bcx.sess()) {
-        trans_msvc_try(bcx, func, data, local_ptr, dest);
+        trans_msvc_try(bcx, ccx, func, data, local_ptr, dest);
     } else {
-        trans_gnu_try(bcx, func, data, local_ptr, dest);
+        trans_gnu_try(bcx, ccx, func, data, local_ptr, dest);
     }
 }
 
@@ -712,24 +707,25 @@ fn try_intrinsic<'a, 'tcx>(
 // instructions are meant to work for all targets, as of the time of this
 // writing, however, LLVM does not recommend the usage of these new instructions
 // as the old ones are still more optimized.
-fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
+                            ccx: &CrateContext,
                             func: ValueRef,
                             data: ValueRef,
                             local_ptr: ValueRef,
                             dest: ValueRef) {
-    let llfn = get_rust_try_fn(bcx.fcx(), &mut |bcx| {
+    let llfn = get_rust_try_fn(ccx, &mut |bcx| {
         let ccx = bcx.ccx;
 
         bcx.set_personality_fn(bcx.ccx.eh_personality());
 
-        let normal = bcx.fcx().build_new_block("normal");
-        let catchswitch = bcx.fcx().build_new_block("catchswitch");
-        let catchpad = bcx.fcx().build_new_block("catchpad");
-        let caught = bcx.fcx().build_new_block("caught");
+        let normal = bcx.build_sibling_block("normal");
+        let catchswitch = bcx.build_sibling_block("catchswitch");
+        let catchpad = bcx.build_sibling_block("catchpad");
+        let caught = bcx.build_sibling_block("caught");
 
-        let func = llvm::get_param(bcx.fcx().llfn, 0);
-        let data = llvm::get_param(bcx.fcx().llfn, 1);
-        let local_ptr = llvm::get_param(bcx.fcx().llfn, 2);
+        let func = llvm::get_param(bcx.llfn(), 0);
+        let data = llvm::get_param(bcx.llfn(), 1);
+        let local_ptr = llvm::get_param(bcx.llfn(), 2);
 
         // We're generating an IR snippet that looks like:
         //
@@ -771,7 +767,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
         //
         // More information can be found in libstd's seh.rs implementation.
         let i64p = Type::i64(ccx).ptr_to();
-        let slot = bcx.fcx().alloca(i64p, "slot");
+        let slot = bcx.alloca(i64p, "slot");
         bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
             None);
 
@@ -791,8 +787,8 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
         let val1 = C_i32(ccx, 1);
         let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]));
         let local_ptr = catchpad.bitcast(local_ptr, i64p);
-        catchpad.store(arg1, local_ptr);
-        catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]));
+        catchpad.store(arg1, local_ptr, None);
+        catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), None);
         catchpad.catch_ret(tok, caught.llbb());
 
         caught.ret(C_i32(ccx, 1));
@@ -801,7 +797,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
     let ret = bcx.call(llfn, &[func, data, local_ptr], None);
-    bcx.store(ret, dest);
+    bcx.store(ret, dest, None);
 }
 
 // Definition of the standard "try" function for Rust using the GNU-like model
@@ -815,12 +811,13 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
 // function calling it, and that function may already have other personality
 // functions in play. By calling a shim we're guaranteed that our shim will have
 // the right personality function.
-fn trans_gnu_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+fn trans_gnu_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
+                           ccx: &CrateContext,
                            func: ValueRef,
                            data: ValueRef,
                            local_ptr: ValueRef,
                            dest: ValueRef) {
-    let llfn = get_rust_try_fn(bcx.fcx(), &mut |bcx| {
+    let llfn = get_rust_try_fn(ccx, &mut |bcx| {
         let ccx = bcx.ccx;
 
         // Translates the shims described above:
@@ -840,12 +837,12 @@ fn trans_gnu_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
         // expected to be `*mut *mut u8` for this to actually work, but that's
         // managed by the standard library.
 
-        let then = bcx.fcx().build_new_block("then");
-        let catch = bcx.fcx().build_new_block("catch");
+        let then = bcx.build_sibling_block("then");
+        let catch = bcx.build_sibling_block("catch");
 
-        let func = llvm::get_param(bcx.fcx().llfn, 0);
-        let data = llvm::get_param(bcx.fcx().llfn, 1);
-        let local_ptr = llvm::get_param(bcx.fcx().llfn, 2);
+        let func = llvm::get_param(bcx.llfn(), 0);
+        let data = llvm::get_param(bcx.llfn(), 1);
+        let local_ptr = llvm::get_param(bcx.llfn(), 2);
         bcx.invoke(func, &[data], then.llbb(), catch.llbb(), None);
         then.ret(C_i32(ccx, 0));
 
@@ -857,28 +854,27 @@ fn trans_gnu_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
         // rust_try ignores the selector.
         let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
                                     false);
-        let vals = catch.landing_pad(lpad_ty, bcx.ccx.eh_personality(), 1, catch.fcx().llfn);
+        let vals = catch.landing_pad(lpad_ty, bcx.ccx.eh_personality(), 1, catch.llfn());
         catch.add_clause(vals, C_null(Type::i8p(ccx)));
         let ptr = catch.extract_value(vals, 0);
-        catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(ccx).ptr_to()));
+        catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(ccx).ptr_to()), None);
         catch.ret(C_i32(ccx, 1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
     let ret = bcx.call(llfn, &[func, data, local_ptr], None);
-    bcx.store(ret, dest);
+    bcx.store(ret, dest, None);
 }
 
 // Helper function to give a Block to a closure to translate a shim function.
 // This is currently primarily used for the `try` intrinsic functions above.
-fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+fn gen_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     name: &str,
                     inputs: Vec<Ty<'tcx>>,
                     output: Ty<'tcx>,
-                    trans: &mut for<'b> FnMut(BlockAndBuilder<'b, 'tcx>))
+                    trans: &mut for<'b> FnMut(Builder<'b, 'tcx>))
                     -> ValueRef {
-    let ccx = fcx.ccx;
     let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
 
     let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
@@ -887,8 +883,8 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         sig: ty::Binder(sig)
     }));
     let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
-    let fcx = FunctionContext::new(ccx, llfn);
-    trans(fcx.get_entry_block());
+    let bcx = Builder::new_block(ccx, llfn, "entry-block");
+    trans(bcx);
     llfn
 }
 
@@ -896,10 +892,9 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
 // catch exceptions.
 //
 // This function is only generated once and is then cached.
-fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
-                             trans: &mut for<'b> FnMut(BlockAndBuilder<'b, 'tcx>))
+fn get_rust_try_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                             trans: &mut for<'b> FnMut(Builder<'b, 'tcx>))
                              -> ValueRef {
-    let ccx = fcx.ccx;
     if let Some(llfn) = ccx.rust_try_fn().get() {
         return llfn;
     }
@@ -913,7 +908,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)),
     }));
     let output = tcx.types.i32;
-    let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
+    let rust_try = gen_fn(ccx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
     ccx.rust_try_fn().set(Some(rust_try));
     return rust_try
 }
@@ -923,7 +918,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
 }
 
 fn generic_simd_intrinsic<'a, 'tcx>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     name: &str,
     callee_ty: Ty<'tcx>,
     llargs: &[ValueRef],
index cf50e7be2afb5c1692b3532ec84b0f33d5d1f3ae..aecba2f57e52cd156d0324f80fbf9f6c275d325e 100644 (file)
@@ -13,6 +13,7 @@
 use rustc::traits;
 use callee::{Callee, CalleeData};
 use common::*;
+use builder::Builder;
 use consts;
 use declare;
 use glue;
@@ -27,7 +28,7 @@
 const VTABLE_OFFSET: usize = 3;
 
 /// Extracts a method from a trait object's vtable, at the specified index.
-pub fn get_virtual_method<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                     llvtable: ValueRef,
                                     vtable_index: usize)
                                     -> ValueRef {
@@ -75,10 +76,9 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
 
-    let fcx = FunctionContext::new(ccx, llfn);
-    let bcx = fcx.get_entry_block();
+    let bcx = Builder::new_block(ccx, llfn, "entry-block");
 
-    let mut llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(llfn);
     let fn_ret = callee.ty.fn_ret();
     let fn_ty = callee.direct_fn_type(ccx, &[]);
 
index ecedcd68382d167ad44ef8d6d852472ab8cb112b..7d4a1ab5ae70e1f7b991934c94d1e0dbf036f60a 100644 (file)
 use rustc::ty::{self, layout};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
-use adt::{self, MaybeSizedValue};
+use adt;
 use base::{self, Lifetime};
 use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
-use common::{self, BlockAndBuilder, Funclet};
+use builder::Builder;
+use common::{self, Funclet};
 use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
 use consts;
 use Disr;
 use machine::{llalign_of_min, llbitsize_of_real};
 use meth;
-use type_of;
+use type_of::{self, align_of};
 use glue;
 use type_::Type;
 
 use rustc_data_structures::fx::FxHashMap;
 use syntax::symbol::Symbol;
 
+use std::cmp;
+
 use super::{MirContext, LocalRef};
 use super::analyze::CleanupKind;
 use super::constant::Const;
-use super::lvalue::{LvalueRef};
+use super::lvalue::LvalueRef;
 use super::operand::OperandRef;
 use super::operand::OperandValue::{Pair, Ref, Immediate};
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_block(&mut self, bb: mir::BasicBlock,
         funclets: &IndexVec<mir::BasicBlock, Option<Funclet>>) {
-        let mut bcx = self.build_block(bb);
+        let mut bcx = self.get_builder(bb);
         let data = &self.mir[bb];
 
         debug!("trans_block({:?}={:?})", bb, data);
@@ -55,7 +58,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
         let cleanup_pad = funclet.map(|lp| lp.cleanuppad());
         let cleanup_bundle = funclet.map(|l| l.bundle());
 
-        let funclet_br = |this: &Self, bcx: BlockAndBuilder, bb: mir::BasicBlock| {
+        let funclet_br = |this: &Self, bcx: Builder, bb: mir::BasicBlock| {
             let lltarget = this.blocks[bb];
             if let Some(cp) = cleanup_pad {
                 match this.cleanup_kinds[bb] {
@@ -82,7 +85,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
 
                         debug!("llblock: creating cleanup trampoline for {:?}", target);
                         let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target);
-                        let trampoline = this.fcx.build_new_block(name);
+                        let trampoline = this.new_block(name);
                         trampoline.cleanup_ret(cp, Some(lltarget));
                         trampoline.llbb()
                     }
@@ -206,8 +209,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     };
                     let llslot = match op.val {
                         Immediate(_) | Pair(..) => {
-                            let llscratch = bcx.fcx().alloca(ret.original_ty, "ret");
-                            self.store_operand(&bcx, llscratch, op);
+                            let llscratch = bcx.alloca(ret.original_ty, "ret");
+                            self.store_operand(&bcx, llscratch, op, None);
                             llscratch
                         }
                         Ref(llval) => llval
@@ -220,7 +223,11 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     load
                 } else {
                     let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
-                    op.pack_if_pair(&bcx).immediate()
+                    if let Ref(llval) = op.val {
+                        base::load_ty(&bcx, llval, op.ty)
+                    } else {
+                        op.pack_if_pair(&bcx).immediate()
+                    }
                 };
                 bcx.ret(llval);
             }
@@ -239,20 +246,14 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     return;
                 }
 
-                let lvalue = self.trans_lvalue(&bcx, location);
+                let mut lvalue = self.trans_lvalue(&bcx, location);
                 let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
                 let drop_ty = glue::get_drop_glue_type(bcx.ccx.shared(), ty);
-                let ptr = if bcx.ccx.shared().type_is_sized(ty) {
-                    let value = if drop_ty != ty {
-                        bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to())
-                    } else {
-                        lvalue.llval
-                    };
-                    MaybeSizedValue::sized(value)
-                } else {
-                    MaybeSizedValue::unsized_(lvalue.llval, lvalue.llextra)
-                };
-                let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
+                if bcx.ccx.shared().type_is_sized(ty) && drop_ty != ty {
+                    lvalue.llval = bcx.pointercast(
+                        lvalue.llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to());
+                }
+                let args = &[lvalue.llval, lvalue.llextra][..1 + lvalue.has_extra() as usize];
                 if let Some(unwind) = unwind {
                     bcx.invoke(
                         drop_fn,
@@ -299,7 +300,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
 
                 // Create the failure block and the conditional branch to it.
                 let lltarget = llblock(self, target);
-                let panic_block = self.fcx.build_new_block("panic");
+                let panic_block = self.new_block("panic");
                 if expected {
                     bcx.cond_br(cond, lltarget, panic_block.llbb());
                 } else {
@@ -424,7 +425,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     // The first argument is a thin destination pointer.
                     let llptr = self.trans_operand(&bcx, &args[0]).immediate();
                     let val = self.trans_operand(&bcx, &args[1]);
-                    self.store_operand(&bcx, llptr, val);
+                    self.store_operand(&bcx, llptr, val, None);
                     funclet_br(self, bcx, target);
                     return;
                 }
@@ -582,15 +583,13 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                     fn_ty.apply_attrs_callsite(invokeret);
 
                     if let Some((_, target)) = *destination {
-                        let ret_bcx = self.build_block(target);
-                        ret_bcx.at_start(|ret_bcx| {
-                            self.set_debug_loc(&ret_bcx, terminator.source_info);
-                            let op = OperandRef {
-                                val: Immediate(invokeret),
-                                ty: sig.output(),
-                            };
-                            self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
-                        });
+                        let ret_bcx = self.get_builder(target);
+                        self.set_debug_loc(&ret_bcx, terminator.source_info);
+                        let op = OperandRef {
+                            val: Immediate(invokeret),
+                            ty: sig.output(),
+                        };
+                        self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
                     }
                 } else {
                     let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
@@ -611,7 +610,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
     }
 
     fn trans_argument(&mut self,
-                      bcx: &BlockAndBuilder<'a, 'tcx>,
+                      bcx: &Builder<'a, 'tcx>,
                       op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
                       fn_ty: &FnType,
@@ -656,8 +655,8 @@ fn trans_argument(&mut self,
         let (mut llval, by_ref) = match op.val {
             Immediate(_) | Pair(..) => {
                 if arg.is_indirect() || arg.cast.is_some() {
-                    let llscratch = bcx.fcx().alloca(arg.original_ty, "arg");
-                    self.store_operand(bcx, llscratch, op);
+                    let llscratch = bcx.alloca(arg.original_ty, "arg");
+                    self.store_operand(bcx, llscratch, op, None);
                     (llscratch, true)
                 } else {
                     (op.pack_if_pair(bcx).immediate(), false)
@@ -687,7 +686,7 @@ fn trans_argument(&mut self,
     }
 
     fn trans_arguments_untupled(&mut self,
-                                bcx: &BlockAndBuilder<'a, 'tcx>,
+                                bcx: &Builder<'a, 'tcx>,
                                 operand: &mir::Operand<'tcx>,
                                 llargs: &mut Vec<ValueRef>,
                                 fn_ty: &FnType,
@@ -704,9 +703,9 @@ fn trans_arguments_untupled(&mut self,
         // Handle both by-ref and immediate tuples.
         match tuple.val {
             Ref(llval) => {
-                let base = adt::MaybeSizedValue::sized(llval);
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let ptr = adt::trans_field_ptr(bcx, tuple.ty, base, Disr(0), n);
+                    let ptr = LvalueRef::new_sized_ty(llval, tuple.ty);
+                    let ptr = ptr.trans_field_ptr(bcx, n);
                     let val = if common::type_is_fat_ptr(bcx.ccx, ty) {
                         let (lldata, llextra) = base::load_fat_ptr(bcx, ptr, ty);
                         Pair(lldata, llextra)
@@ -763,13 +762,13 @@ fn trans_arguments_untupled(&mut self,
 
     }
 
-    fn get_personality_slot(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>) -> ValueRef {
+    fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
         let ccx = bcx.ccx;
         if let Some(slot) = self.llpersonalityslot {
             slot
         } else {
             let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
-            let slot = bcx.fcx().alloca(llretty, "personalityslot");
+            let slot = bcx.alloca(llretty, "personalityslot");
             self.llpersonalityslot = Some(slot);
             Lifetime::Start.call(bcx, slot);
             slot
@@ -788,36 +787,42 @@ fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> BasicBlockRef {
             return self.blocks[target_bb];
         }
 
-        let target = self.build_block(target_bb);
+        let target = self.get_builder(target_bb);
 
-        let bcx = self.fcx.build_new_block("cleanup");
+        let bcx = self.new_block("cleanup");
         self.landing_pads[target_bb] = Some(bcx.llbb());
 
         let ccx = bcx.ccx;
         let llpersonality = self.ccx.eh_personality();
         let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
-        let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.fcx.llfn);
+        let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn);
         bcx.set_cleanup(llretval);
         let slot = self.get_personality_slot(&bcx);
-        bcx.store(llretval, slot);
+        bcx.store(llretval, slot, None);
         bcx.br(target.llbb());
         bcx.llbb()
     }
 
     fn unreachable_block(&mut self) -> BasicBlockRef {
         self.unreachable_block.unwrap_or_else(|| {
-            let bl = self.fcx.build_new_block("unreachable");
+            let bl = self.new_block("unreachable");
             bl.unreachable();
             self.unreachable_block = Some(bl.llbb());
             bl.llbb()
         })
     }
 
-    pub fn build_block(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'a, 'tcx> {
-        BlockAndBuilder::new(self.blocks[bb], self.fcx)
+    pub fn new_block(&self, name: &str) -> Builder<'a, 'tcx> {
+        Builder::new_block(self.ccx, self.llfn, name)
+    }
+
+    pub fn get_builder(&self, bb: mir::BasicBlock) -> Builder<'a, 'tcx> {
+        let builder = Builder::with_ccx(self.ccx);
+        builder.position_at_end(self.blocks[bb]);
+        builder
     }
 
-    fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
+    fn make_return_dest(&mut self, bcx: &Builder<'a, 'tcx>,
                         dest: &mir::Lvalue<'tcx>, fn_ret_ty: &ArgType,
                         llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest {
         // If the return is ignored, we can just return a do-nothing ReturnDest
@@ -834,14 +839,14 @@ fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
                     return if fn_ret_ty.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = base::alloc_ty(bcx, ret_ty, "tmp_ret");
+                        let tmp = bcx.alloca_ty(ret_ty, "tmp_ret");
                         llargs.push(tmp);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else if is_intrinsic {
                         // Currently, intrinsics always need a location to store
                         // the result. so we create a temporary alloca for the
                         // result
-                        let tmp = base::alloc_ty(bcx, ret_ty, "tmp_ret");
+                        let tmp = bcx.alloca_ty(ret_ty, "tmp_ret");
                         ReturnDest::IndirectOperand(tmp, index)
                     } else {
                         ReturnDest::DirectOperand(index)
@@ -862,7 +867,7 @@ fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
         }
     }
 
-    fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
+    fn trans_transmute(&mut self, bcx: &Builder<'a, 'tcx>,
                        src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) {
         let mut val = self.trans_operand(bcx, src);
         if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
@@ -884,13 +889,16 @@ fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
 
         let llty = type_of::type_of(bcx.ccx, val.ty);
         let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
-        self.store_operand(bcx, cast_ptr, val);
+        let in_type = val.ty;
+        let out_type = dst.ty.to_ty(bcx.tcx());;
+        let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
+        self.store_operand(bcx, cast_ptr, val, Some(llalign));
     }
 
 
     // Stores the return value of a function call into it's final location.
     fn store_return(&mut self,
-                    bcx: &BlockAndBuilder<'a, 'tcx>,
+                    bcx: &Builder<'a, 'tcx>,
                     dest: ReturnDest,
                     ret_ty: ArgType,
                     op: OperandRef<'tcx>) {
@@ -906,7 +914,7 @@ fn store_return(&mut self,
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if ret_ty.cast.is_some() {
-                    let tmp = base::alloc_ty(bcx, op.ty, "tmp_ret");
+                    let tmp = bcx.alloca_ty(op.ty, "tmp_ret");
                     ret_ty.store(bcx, op.immediate(), tmp);
                     self.trans_load(bcx, tmp, op.ty)
                 } else {
index 700894c255da68de83680cd580a2ce7c92f00502..13e659a5ae0e8cb7149e052489cbd2689b30f962 100644 (file)
 use rustc::infer::TransNormalize;
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use {abi, adt, base, Disr, machine};
 use callee::Callee;
-use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
+use builder::Builder;
+use common::{self, CrateContext, const_get_elt, val_ty};
 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
-use common::{const_to_opt_u128};
+use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
+use common::const_to_opt_u128;
 use consts;
 use monomorphize::{self, Instance};
 use type_of;
@@ -548,16 +549,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     mir::AggregateKind::Adt(..) |
                     mir::AggregateKind::Closure(..) |
                     mir::AggregateKind::Tuple => {
-                        let disr = match *kind {
-                            mir::AggregateKind::Adt(adt_def, index, _, _) => {
-                                Disr::from(adt_def.variants[index].disr_val)
-                            }
-                            _ => Disr(0)
-                        };
-                        Const::new(
-                            adt::trans_const(self.ccx, dest_ty, disr, &fields),
-                            dest_ty
-                        )
+                        Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty)
                     }
                 }
             }
@@ -900,7 +892,7 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_constant(&mut self,
-                          bcx: &BlockAndBuilder<'a, 'tcx>,
+                          bcx: &Builder<'a, 'tcx>,
                           constant: &mir::Constant<'tcx>)
                           -> Const<'tcx>
     {
@@ -945,3 +937,159 @@ pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
+
+/// Construct a constant value, suitable for initializing a
+/// GlobalVariable, given a case and constant values for its fields.
+/// Note that this may have a different LLVM type (and different
+/// alignment!) from the representation's `type_of`, so it needs a
+/// pointer cast before use.
+///
+/// The LLVM type system does not directly support unions, and only
+/// pointers can be bitcast, so a constant (and, by extension, the
+/// GlobalVariable initialized by it) will have a type that can vary
+/// depending on which case of an enum it is.
+///
+/// To understand the alignment situation, consider `enum E { V64(u64),
+/// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
+/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
+/// i32, i32}`, which is 4-byte aligned.
+///
+/// Currently the returned value has the same size as the type, but
+/// this could be changed in the future to avoid allocating unnecessary
+/// space after values of shorter-than-maximum cases.
+fn trans_const<'a, 'tcx>(
+    ccx: &CrateContext<'a, 'tcx>,
+    t: Ty<'tcx>,
+    kind: &mir::AggregateKind,
+    vals: &[ValueRef]
+) -> ValueRef {
+    let l = ccx.layout_of(t);
+    let dl = &ccx.tcx().data_layout;
+    let variant_index = match *kind {
+        mir::AggregateKind::Adt(_, index, _, _) => index,
+        _ => 0,
+    };
+    match *l {
+        layout::CEnum { discr: d, min, max, .. } => {
+            let discr = match *kind {
+                mir::AggregateKind::Adt(adt_def, _, _, _) => {
+                    Disr::from(adt_def.variants[variant_index].disr_val)
+                },
+                _ => Disr(0),
+            };
+            assert_eq!(vals.len(), 0);
+            adt::assert_discr_in_range(Disr(min), Disr(max), discr);
+            C_integral(Type::from_integer(ccx, d), discr.0, true)
+        }
+        layout::General { discr: d, ref variants, .. } => {
+            let variant = &variants[variant_index];
+            let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
+            let mut vals_with_discr = vec![lldiscr];
+            vals_with_discr.extend_from_slice(vals);
+            let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
+            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
+            if needed_padding > 0 {
+                contents.push(padding(ccx, needed_padding));
+            }
+            C_struct(ccx, &contents[..], false)
+        }
+        layout::UntaggedUnion { ref variants, .. }=> {
+            assert_eq!(variant_index, 0);
+            let contents = build_const_union(ccx, variants, vals[0]);
+            C_struct(ccx, &contents, variants.packed)
+        }
+        layout::Univariant { ref variant, .. } => {
+            assert_eq!(variant_index, 0);
+            let contents = build_const_struct(ccx, &variant, vals);
+            C_struct(ccx, &contents[..], variant.packed)
+        }
+        layout::Vector { .. } => {
+            C_vector(vals)
+        }
+        layout::RawNullablePointer { nndiscr, .. } => {
+            let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
+            if variant_index as u64 == nndiscr {
+                assert_eq!(vals.len(), 1);
+                vals[0]
+            } else {
+                C_null(type_of::sizing_type_of(ccx, nnty))
+            }
+        }
+        layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
+            if variant_index as u64 == nndiscr {
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
+            } else {
+                let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
+                let vals = fields.iter().map(|&ty| {
+                    // Always use null even if it's not the `discrfield`th
+                    // field; see #8506.
+                    C_null(type_of::sizing_type_of(ccx, ty))
+                }).collect::<Vec<ValueRef>>();
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
+            }
+        }
+        _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
+    }
+}
+
+/// Building structs is a little complicated, because we might need to
+/// insert padding if a field's value is less aligned than its type.
+///
+/// Continuing the example from `trans_const`, a value of type `(u32,
+/// E)` should have the `E` at offset 8, but if that field's
+/// initializer is 4-byte aligned then simply translating the tuple as
+/// a two-element struct will locate it at offset 4, and accesses to it
+/// will read the wrong memory.
+fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                st: &layout::Struct,
+                                vals: &[ValueRef])
+                                -> Vec<ValueRef> {
+    assert_eq!(vals.len(), st.offsets.len());
+
+    if vals.len() == 0 {
+        return Vec::new();
+    }
+
+    // offset of current value
+    let mut offset = 0;
+    let mut cfields = Vec::new();
+    cfields.reserve(st.offsets.len()*2);
+
+    let parts = st.field_index_by_increasing_offset().map(|i| {
+        (&vals[i], st.offsets[i].bytes())
+    });
+    for (&val, target_offset) in parts {
+        if offset < target_offset {
+            cfields.push(padding(ccx, target_offset - offset));
+            offset = target_offset;
+        }
+        assert!(!is_undef(val));
+        cfields.push(val);
+        offset += machine::llsize_of_alloc(ccx, val_ty(val));
+    }
+
+    if offset < st.stride().bytes() {
+        cfields.push(padding(ccx, st.stride().bytes() - offset));
+    }
+
+    cfields
+}
+
+fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               un: &layout::Union,
+                               field_val: ValueRef)
+                               -> Vec<ValueRef> {
+    let mut cfields = vec![field_val];
+
+    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
+    let size = un.stride().bytes();
+    if offset != size {
+        cfields.push(padding(ccx, size - offset));
+    }
+
+    cfields
+}
+
+fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
+    C_undef(Type::array(&Type::i8(ccx), size))
+}
index 0cd7f007c5df92dda45b67fee48d100b808ac524..bd6e70639bba540e4396742fdd5187ea5fc0bedf 100644 (file)
@@ -9,18 +9,20 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, layout, Ty, TypeFoldable};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
 use adt;
-use base;
-use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
+use builder::Builder;
+use common::{self, CrateContext, C_uint, C_undef};
 use consts;
 use machine;
 use type_of::type_of;
 use type_of;
-use Disr;
+use type_::Type;
+use value::Value;
+use glue;
 
 use std::ptr;
 
@@ -39,22 +41,24 @@ pub struct LvalueRef<'tcx> {
     pub ty: LvalueTy<'tcx>,
 }
 
-impl<'tcx> LvalueRef<'tcx> {
+impl<'a, 'tcx> LvalueRef<'tcx> {
     pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
         LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
     }
 
-    pub fn alloca<'a>(bcx: &BlockAndBuilder<'a, 'tcx>,
-                        ty: Ty<'tcx>,
-                        name: &str)
-                        -> LvalueRef<'tcx>
-    {
-        assert!(!ty.has_erasable_regions());
-        let lltemp = base::alloc_ty(bcx, ty, name);
-        LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
+    pub fn new_sized_ty(llval: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
+        LvalueRef::new_sized(llval, LvalueTy::from_ty(ty))
+    }
+
+    pub fn new_unsized_ty(llval: ValueRef, llextra: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
+        LvalueRef {
+            llval: llval,
+            llextra: llextra,
+            ty: LvalueTy::from_ty(ty),
+        }
     }
 
-    pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
+    pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         let ty = self.ty.to_ty(ccx.tcx());
         match ty.sty {
             ty::TyArray(_, n) => common::C_uint(ccx, n),
@@ -65,17 +69,170 @@ pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
             _ => bug!("unexpected type `{}` in LvalueRef::len", ty)
         }
     }
+
+    pub fn has_extra(&self) -> bool {
+        !self.llextra.is_null()
+    }
+
+    fn struct_field_ptr(
+        self,
+        bcx: &Builder<'a, 'tcx>,
+        st: &layout::Struct,
+        fields: &Vec<Ty<'tcx>>,
+        ix: usize,
+        needs_cast: bool
+    ) -> ValueRef {
+        let fty = fields[ix];
+        let ccx = bcx.ccx;
+
+        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);
+            bcx.pointercast(self.llval, real_ty.ptr_to())
+        } else {
+            self.llval
+        };
+
+        // Simple case - we can just GEP the field
+        //   * First field - Always aligned properly
+        //   * Packed struct - There is no alignment padding
+        //   * 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);
+            }
+
+        // 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);
+            }
+            _ => ()
+        }
+
+        // There's no metadata available, log the case and just do the GEP.
+        if !self.has_extra() {
+            debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
+                ix, Value(ptr_val));
+            return bcx.struct_gep(ptr_val, ix);
+        }
+
+        // We need to get the pointer manually now.
+        // We do this by casting to a *i8, then offsetting it by the appropriate amount.
+        // We do this instead of, say, simply adjusting the pointer from the result of a GEP
+        // because the field may have an arbitrary alignment in the LLVM representation
+        // anyway.
+        //
+        // To demonstrate:
+        //   struct Foo<T: ?Sized> {
+        //      x: u16,
+        //      y: T
+        //   }
+        //
+        // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
+        // the `y` field has 16-bit alignment.
+
+        let meta = self.llextra;
+
+
+        let offset = st.offsets[ix].bytes();
+        let unaligned_offset = C_uint(bcx.ccx, offset);
+
+        // Get the alignment of the field
+        let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
+
+        // Bump the unaligned offset up to the appropriate alignment using the
+        // following expression:
+        //
+        //   (unaligned offset + (align - 1)) & -align
+
+        // Calculate offset
+        let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
+        let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
+        bcx.neg(align));
+
+        debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
+
+        // Cast and adjust pointer
+        let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx));
+        let byte_ptr = bcx.gep(byte_ptr, &[offset]);
+
+        // Finally, cast back to the type expected
+        let ll_fty = type_of::in_memory_type_of(bcx.ccx, fty);
+        debug!("struct_field_ptr: Field type is {:?}", ll_fty);
+        bcx.pointercast(byte_ptr, ll_fty.ptr_to())
+    }
+
+    /// Access a field, at a point when the value's case is known.
+    pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> ValueRef {
+        let discr = match self.ty {
+            LvalueTy::Ty { .. } => 0,
+            LvalueTy::Downcast { variant_index, .. } => variant_index,
+        };
+        let t = self.ty.to_ty(bcx.tcx());
+        let l = bcx.ccx.layout_of(t);
+        // Note: if this ever needs to generate conditionals (e.g., if we
+        // decide to do some kind of cdr-coding-like non-unique repr
+        // someday), it will need to return a possibly-new bcx as well.
+        match *l {
+            layout::Univariant { ref variant, .. } => {
+                assert_eq!(discr, 0);
+                self.struct_field_ptr(bcx, &variant,
+                    &adt::compute_fields(bcx.ccx, t, 0, false), ix, false)
+            }
+            layout::Vector { count, .. } => {
+                assert_eq!(discr, 0);
+                assert!((ix as u64) < count);
+                bcx.struct_gep(self.llval, ix)
+            }
+            layout::General { discr: d, ref variants, .. } => {
+                let mut fields = adt::compute_fields(bcx.ccx, t, discr, false);
+                fields.insert(0, d.to_ty(&bcx.tcx(), false));
+                self.struct_field_ptr(bcx, &variants[discr], &fields, ix + 1, true)
+            }
+            layout::UntaggedUnion { .. } => {
+                let fields = adt::compute_fields(bcx.ccx, t, 0, false);
+                let ty = type_of::in_memory_type_of(bcx.ccx, fields[ix]);
+                bcx.pointercast(self.llval, ty.ptr_to())
+            }
+            layout::RawNullablePointer { nndiscr, .. } |
+            layout::StructWrappedNullablePointer { nndiscr,  .. } if discr as u64 != nndiscr => {
+                let nullfields = adt::compute_fields(bcx.ccx, t, (1-nndiscr) as usize, false);
+                // The unit-like case might have a nonzero number of unit-like fields.
+                // (e.d., Result of Either with (), as one side.)
+                let ty = type_of::type_of(bcx.ccx, nullfields[ix]);
+                assert_eq!(machine::llsize_of_alloc(bcx.ccx, ty), 0);
+                bcx.pointercast(self.llval, ty.ptr_to())
+            }
+            layout::RawNullablePointer { nndiscr, .. } => {
+                let nnty = adt::compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
+                assert_eq!(ix, 0);
+                assert_eq!(discr as u64, nndiscr);
+                let ty = type_of::type_of(bcx.ccx, nnty);
+                bcx.pointercast(self.llval, ty.ptr_to())
+            }
+            layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
+                assert_eq!(discr as u64, nndiscr);
+                self.struct_field_ptr(bcx, &nonnull,
+                    &adt::compute_fields(bcx.ccx, t, discr, false), ix, false)
+            }
+            _ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
+        }
+    }
 }
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_lvalue(&mut self,
-                        bcx: &BlockAndBuilder<'a, 'tcx>,
+                        bcx: &Builder<'a, 'tcx>,
                         lvalue: &mir::Lvalue<'tcx>)
                         -> LvalueRef<'tcx> {
         debug!("trans_lvalue(lvalue={:?})", lvalue);
 
         let ccx = bcx.ccx;
-        let tcx = bcx.tcx();
+        let tcx = ccx.tcx();
 
         if let mir::Lvalue::Local(index) = *lvalue {
             match self.locals[index] {
@@ -134,26 +291,12 @@ pub fn trans_lvalue(&mut self,
                 let (llprojected, llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
-                        let base_ty = tr_base.ty.to_ty(tcx);
-                        let discr = match tr_base.ty {
-                            LvalueTy::Ty { .. } => 0,
-                            LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
-                        };
-                        let discr = discr as u64;
-                        let is_sized = self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx));
-                        let base = if is_sized {
-                            adt::MaybeSizedValue::sized(tr_base.llval)
-                        } else {
-                            adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
-                        };
-                        let llprojected = adt::trans_field_ptr(bcx, base_ty, base, Disr(discr),
-                            field.index());
-                        let llextra = if is_sized {
+                        let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) {
                             ptr::null_mut()
                         } else {
                             tr_base.llextra
                         };
-                        (llprojected, llextra)
+                        (tr_base.trans_field_ptr(bcx, field.index()), llextra)
                     }
                     mir::ProjectionElem::Index(ref index) => {
                         let index = self.trans_operand(bcx, index);
@@ -214,7 +357,7 @@ pub fn trans_lvalue(&mut self,
     // Perform an action using the given Lvalue.
     // If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
     // is created first, then used as an operand to update the Lvalue.
-    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
+    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &Builder<'a, 'tcx>,
                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
     {
@@ -223,9 +366,9 @@ pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
                 LocalRef::Lvalue(lvalue) => f(self, lvalue),
                 LocalRef::Operand(None) => {
                     let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
-                    let lvalue = LvalueRef::alloca(bcx,
-                                                   lvalue_ty,
-                                                   "lvalue_temp");
+                    assert!(!lvalue_ty.has_erasable_regions());
+                    let lltemp = bcx.alloca_ty(lvalue_ty, "lvalue_temp");
+                    let lvalue = LvalueRef::new_sized(lltemp, LvalueTy::from_ty(lvalue_ty));
                     let ret = f(self, lvalue);
                     let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
                     self.locals[index] = LocalRef::Operand(Some(op));
@@ -254,18 +397,13 @@ pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
     /// than we are.
     ///
     /// nmatsakis: is this still necessary? Not sure.
-    fn prepare_index(&mut self,
-                     bcx: &BlockAndBuilder<'a, 'tcx>,
-                     llindex: ValueRef)
-                     -> ValueRef
-    {
-        let ccx = bcx.ccx;
+    fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef {
         let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
-        let int_size = machine::llbitsize_of_real(bcx.ccx, ccx.int_type());
+        let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.int_type());
         if index_size < int_size {
-            bcx.zext(llindex, ccx.int_type())
+            bcx.zext(llindex, bcx.ccx.int_type())
         } else if index_size > int_size {
-            bcx.trunc(llindex, ccx.int_type())
+            bcx.trunc(llindex, bcx.ccx.int_type())
         } else {
             llindex
         }
index a1373cb9482b7b17861a5a008c2e708c700c83b5..eedd7956805b6a52fb7a43a074e27496ae387d7a 100644 (file)
@@ -19,7 +19,8 @@
 use rustc::ty::TypeFoldable;
 use session::config::FullDebugInfo;
 use base;
-use common::{self, BlockAndBuilder, CrateContext, FunctionContext, C_null, Funclet};
+use builder::Builder;
+use common::{self, CrateContext, C_null, Funclet};
 use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
 use monomorphize::{self, Instance};
 use abi::FnType;
@@ -37,7 +38,7 @@
 pub use self::constant::trans_static_initializer;
 
 use self::analyze::CleanupKind;
-use self::lvalue::{LvalueRef};
+use self::lvalue::LvalueRef;
 use rustc::mir::traversal;
 
 use self::operand::{OperandRef, OperandValue};
@@ -48,7 +49,7 @@ pub struct MirContext<'a, 'tcx:'a> {
 
     debug_context: debuginfo::FunctionDebugContext,
 
-    fcx: &'a common::FunctionContext<'a, 'tcx>,
+    llfn: ValueRef,
 
     ccx: &'a CrateContext<'a, 'tcx>,
 
@@ -106,7 +107,7 @@ pub fn monomorphize<T>(&self, value: &T) -> T
         monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value)
     }
 
-    pub fn set_debug_loc(&mut self, bcx: &BlockAndBuilder, source_info: mir::SourceInfo) {
+    pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) {
         let (scope, span) = self.debug_loc(source_info);
         debuginfo::set_source_location(&self.debug_context, bcx, scope, span);
     }
@@ -198,7 +199,8 @@ fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>,
 ///////////////////////////////////////////////////////////////////////////
 
 pub fn trans_mir<'a, 'tcx: 'a>(
-    fcx: &'a FunctionContext<'a, 'tcx>,
+    ccx: &'a CrateContext<'a, 'tcx>,
+    llfn: ValueRef,
     fn_ty: FnType,
     mir: &'a Mir<'tcx>,
     instance: Instance<'tcx>,
@@ -207,8 +209,8 @@ pub fn trans_mir<'a, 'tcx: 'a>(
 ) {
     debug!("fn_ty: {:?}", fn_ty);
     let debug_context =
-        debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir);
-    let bcx = fcx.get_entry_block();
+        debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfn, mir);
+    let bcx = Builder::new_block(ccx, llfn, "entry-block");
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
 
@@ -216,20 +218,20 @@ pub fn trans_mir<'a, 'tcx: 'a>(
     let block_bcxs: IndexVec<mir::BasicBlock, BasicBlockRef> =
         mir.basic_blocks().indices().map(|bb| {
             if bb == mir::START_BLOCK {
-                fcx.new_block("start")
+                bcx.build_sibling_block("start").llbb()
             } else {
-                fcx.new_block(&format!("{:?}", bb))
+                bcx.build_sibling_block(&format!("{:?}", bb)).llbb()
             }
         }).collect();
 
     // Compute debuginfo scopes from MIR scopes.
-    let scopes = debuginfo::create_mir_scopes(fcx, mir, &debug_context);
+    let scopes = debuginfo::create_mir_scopes(ccx, mir, &debug_context);
 
     let mut mircx = MirContext {
         mir: mir,
-        fcx: fcx,
+        llfn: llfn,
         fn_ty: fn_ty,
-        ccx: fcx.ccx,
+        ccx: ccx,
         llpersonalityslot: None,
         blocks: block_bcxs,
         unreachable_block: None,
@@ -266,7 +268,9 @@ pub fn trans_mir<'a, 'tcx: 'a>(
                 }
 
                 debug!("alloc: {:?} ({}) -> lvalue", local, name);
-                let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
+                assert!(!ty.has_erasable_regions());
+                let lltemp = bcx.alloca_ty(ty, &name.as_str());
+                let lvalue = LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty));
                 if dbg {
                     let (scope, span) = mircx.debug_loc(source_info);
                     declare_local(&bcx, &mircx.debug_context, name, ty, scope,
@@ -278,11 +282,13 @@ pub fn trans_mir<'a, 'tcx: 'a>(
                 // Temporary or return pointer
                 if local == mir::RETURN_POINTER && mircx.fn_ty.ret.is_indirect() {
                     debug!("alloc: {:?} (return pointer) -> lvalue", local);
-                    let llretptr = llvm::get_param(fcx.llfn, 0);
+                    let llretptr = llvm::get_param(llfn, 0);
                     LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
                 } else if lvalue_locals.contains(local.index()) {
                     debug!("alloc: {:?} -> lvalue", local);
-                    LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
+                    assert!(!ty.has_erasable_regions());
+                    let lltemp = bcx.alloca_ty(ty, &format!("{:?}", local));
+                    LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty)))
                 } else {
                     // If this is an immediate local, we do not create an
                     // alloca in advance. Instead we wait until we see the
@@ -312,9 +318,9 @@ pub fn trans_mir<'a, 'tcx: 'a>(
     let funclets: IndexVec<mir::BasicBlock, Option<Funclet>> =
     mircx.cleanup_kinds.iter_enumerated().map(|(bb, cleanup_kind)| {
         if let CleanupKind::Funclet = *cleanup_kind {
-            let bcx = mircx.build_block(bb);
+            let bcx = mircx.get_builder(bb);
             bcx.set_personality_fn(mircx.ccx.eh_personality());
-            if base::wants_msvc_seh(fcx.ccx.sess()) {
+            if base::wants_msvc_seh(ccx.sess()) {
                 return Some(Funclet::new(bcx.cleanup_pad(None, &[])));
             }
         }
@@ -347,13 +353,12 @@ pub fn trans_mir<'a, 'tcx: 'a>(
 /// Produce, for each argument, a `ValueRef` pointing at the
 /// argument's value. As arguments are lvalues, these are always
 /// indirect.
-fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                             mircx: &MirContext<'a, 'tcx>,
                             scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
                             lvalue_locals: &BitVector)
                             -> Vec<LocalRef<'tcx>> {
     let mir = mircx.mir;
-    let fcx = bcx.fcx();
     let tcx = bcx.tcx();
     let mut idx = 0;
     let mut llarg_idx = mircx.fn_ty.ret.is_indirect() as usize;
@@ -381,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
+            let lltemp = bcx.alloca_ty(arg_ty, &format!("arg{}", arg_index));
             for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
                 let dst = bcx.struct_gep(lltemp, i);
                 let arg = &mircx.fn_ty.args[idx];
@@ -428,7 +433,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
             if arg.pad.is_some() {
                 llarg_idx += 1;
             }
-            let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
+            let llarg = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
             llarg_idx += 1;
             llarg
         } else if !lvalue_locals.contains(local.index()) &&
@@ -444,13 +449,13 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
             if arg.pad.is_some() {
                 llarg_idx += 1;
             }
-            let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
+            let llarg = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
             llarg_idx += 1;
             let val = if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
                 let meta = &mircx.fn_ty.args[idx];
                 idx += 1;
                 assert_eq!((meta.cast, meta.pad), (None, None));
-                let llmeta = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
+                let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
                 llarg_idx += 1;
                 OperandValue::Pair(llarg, llmeta)
             } else {
@@ -462,7 +467,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
             };
             return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
         } else {
-            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
+            let lltemp = bcx.alloca_ty(arg_ty, &format!("arg{}", arg_index));
             if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
                 // we pass fat pointers as two words, but we want to
                 // represent them internally as a pointer to two words,
@@ -514,8 +519,8 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'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.fcx().alloca(common::val_ty(llval), "__debuginfo_env_ptr");
-                bcx.store(llval, alloc);
+                let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr");
+                bcx.store(llval, alloc, None);
                 alloc
             } else {
                 llval
@@ -573,7 +578,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
 mod analyze;
 mod block;
 mod constant;
-mod lvalue;
+pub mod lvalue;
 mod operand;
 mod rvalue;
 mod statement;
index 526155655af2778b45fd62bbed866992ae43a752..28a247ee612a9078b6ba32322613439e40abb8b4 100644 (file)
@@ -14,7 +14,8 @@
 use rustc_data_structures::indexed_vec::Idx;
 
 use base;
-use common::{self, BlockAndBuilder};
+use common;
+use builder::Builder;
 use value::Value;
 use type_of;
 use type_::Type;
@@ -85,8 +86,7 @@ pub fn immediate(self) -> ValueRef {
 
     /// If this operand is a Pair, we return an
     /// Immediate aggregate with the two values.
-    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
-                        -> OperandRef<'tcx> {
+    pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
         if let OperandValue::Pair(a, b) = self.val {
             // Reconstruct the immediate aggregate.
             let llty = type_of::type_of(bcx.ccx, self.ty);
@@ -107,8 +107,7 @@ pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
 
     /// If this operand is a pair in an Immediate,
     /// we return a Pair with the two halves.
-    pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
-                          -> OperandRef<'tcx> {
+    pub fn unpack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
         if let OperandValue::Immediate(llval) = self.val {
             // Deconstruct the immediate aggregate.
             if common::type_is_imm_pair(bcx.ccx, self.ty) {
@@ -136,7 +135,7 @@ pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_load(&mut self,
-                      bcx: &BlockAndBuilder<'a, 'tcx>,
+                      bcx: &Builder<'a, 'tcx>,
                       llval: ValueRef,
                       ty: Ty<'tcx>)
                       -> OperandRef<'tcx>
@@ -165,7 +164,7 @@ pub fn trans_load(&mut self,
     }
 
     pub fn trans_consume(&mut self,
-                         bcx: &BlockAndBuilder<'a, 'tcx>,
+                         bcx: &Builder<'a, 'tcx>,
                          lvalue: &mir::Lvalue<'tcx>)
                          -> OperandRef<'tcx>
     {
@@ -217,7 +216,7 @@ pub fn trans_consume(&mut self,
     }
 
     pub fn trans_operand(&mut self,
-                         bcx: &BlockAndBuilder<'a, 'tcx>,
+                         bcx: &Builder<'a, 'tcx>,
                          operand: &mir::Operand<'tcx>)
                          -> OperandRef<'tcx>
     {
@@ -242,23 +241,26 @@ pub fn trans_operand(&mut self,
     }
 
     pub fn store_operand(&mut self,
-                         bcx: &BlockAndBuilder<'a, 'tcx>,
+                         bcx: &Builder<'a, 'tcx>,
                          lldest: ValueRef,
-                         operand: OperandRef<'tcx>) {
-        debug!("store_operand: operand={:?}", operand);
+                         operand: OperandRef<'tcx>,
+                         align: Option<u32>) {
+        debug!("store_operand: operand={:?}, align={:?}", operand, align);
         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
         // value is through `undef`, and store itself is useless.
         if common::type_is_zero_size(bcx.ccx, operand.ty) {
             return;
         }
         match operand.val {
-            OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
-            OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
+            OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty, align),
+            OperandValue::Immediate(s) => {
+                bcx.store(base::from_immediate(bcx, s), lldest, align);
+            }
             OperandValue::Pair(a, b) => {
                 let a = base::from_immediate(bcx, a);
                 let b = base::from_immediate(bcx, b);
-                bcx.store(a, bcx.struct_gep(lldest, 0));
-                bcx.store(b, bcx.struct_gep(lldest, 1));
+                bcx.store(a, bcx.struct_gep(lldest, 0), align);
+                bcx.store(b, bcx.struct_gep(lldest, 1), align);
             }
         }
     }
index cca48737bb963e7d6dbb703c6e85c5c76fd50bcb..67fb8cf576d6218afdeafd7bf834024cde76f6de 100644 (file)
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
+use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
 
 use asm;
 use base;
+use builder::Builder;
 use callee::Callee;
-use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder};
+use common::{self, val_ty, C_bool, C_null, C_uint};
 use common::{C_integral};
 use adt;
 use machine;
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_rvalue(&mut self,
-                        bcx: BlockAndBuilder<'a, 'tcx>,
+                        bcx: Builder<'a, 'tcx>,
                         dest: LvalueRef<'tcx>,
                         rvalue: &mir::Rvalue<'tcx>)
-                        -> BlockAndBuilder<'a, 'tcx>
+                        -> Builder<'a, 'tcx>
     {
         debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})",
                Value(dest.llval), rvalue);
@@ -48,7 +50,7 @@ pub fn trans_rvalue(&mut self,
                let tr_operand = self.trans_operand(&bcx, operand);
                // FIXME: consider not copying constants through stack. (fixable by translating
                // constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
-               self.store_operand(&bcx, dest.llval, tr_operand);
+               self.store_operand(&bcx, dest.llval, tr_operand, None);
                bcx
            }
 
@@ -59,7 +61,7 @@ pub fn trans_rvalue(&mut self,
                     // into-coerce of a thin pointer to a fat pointer - just
                     // use the operand path.
                     let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
-                    self.store_operand(&bcx, dest.llval, temp);
+                    self.store_operand(&bcx, dest.llval, temp, None);
                     return bcx;
                 }
 
@@ -79,7 +81,7 @@ pub fn trans_rvalue(&mut self,
                         // index into the struct, and this case isn't
                         // important enough for it.
                         debug!("trans_rvalue: creating ugly alloca");
-                        let lltemp = base::alloc_ty(&bcx, operand.ty, "__unsize_temp");
+                        let lltemp = bcx.alloca_ty(operand.ty, "__unsize_temp");
                         base::store_ty(&bcx, llval, lltemp, operand.ty);
                         lltemp
                     }
@@ -95,13 +97,13 @@ pub fn trans_rvalue(&mut self,
                 let size = C_uint(bcx.ccx, size);
                 let base = base::get_dataptr(&bcx, dest.llval);
                 tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| {
-                    self.store_operand(bcx, llslot, tr_elem);
+                    self.store_operand(bcx, llslot, tr_elem, None);
                 })
             }
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
-                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
+                    mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
                         let disr = Disr::from(adt_def.variants[variant_index].disr_val);
                         let dest_ty = dest.ty.to_ty(bcx.tcx());
                         adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(disr));
@@ -109,11 +111,15 @@ pub fn trans_rvalue(&mut self,
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
                             if !common::type_is_zero_size(bcx.ccx, op.ty) {
-                                let val = adt::MaybeSizedValue::sized(dest.llval);
+                                let mut val = LvalueRef::new_sized(dest.llval, dest.ty);
                                 let field_index = active_field_index.unwrap_or(i);
-                                let lldest_i = adt::trans_field_ptr(&bcx, dest_ty, val, disr,
-                                    field_index);
-                                self.store_operand(&bcx, lldest_i, op);
+                                val.ty = LvalueTy::Downcast {
+                                    adt_def: adt_def,
+                                    substs: self.monomorphize(&substs),
+                                    variant_index: disr.0 as usize,
+                                };
+                                let lldest_i = val.trans_field_ptr(&bcx, field_index);
+                                self.store_operand(&bcx, lldest_i, op, None);
                             }
                         }
                     },
@@ -138,7 +144,7 @@ pub fn trans_rvalue(&mut self,
                                     i
                                 };
                                 let dest = bcx.gepi(dest.llval, &[0, i]);
-                                self.store_operand(&bcx, dest, op);
+                                self.store_operand(&bcx, dest, op, None);
                             }
                         }
                     }
@@ -163,16 +169,16 @@ pub fn trans_rvalue(&mut self,
             _ => {
                 assert!(rvalue_creates_operand(rvalue));
                 let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
-                self.store_operand(&bcx, dest.llval, temp);
+                self.store_operand(&bcx, dest.llval, temp, None);
                 bcx
             }
         }
     }
 
     pub fn trans_rvalue_operand(&mut self,
-                                bcx: BlockAndBuilder<'a, 'tcx>,
+                                bcx: Builder<'a, 'tcx>,
                                 rvalue: &mir::Rvalue<'tcx>)
-                                -> (BlockAndBuilder<'a, 'tcx>, OperandRef<'tcx>)
+                                -> (Builder<'a, 'tcx>, OperandRef<'tcx>)
     {
         assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
 
@@ -477,7 +483,7 @@ pub fn trans_rvalue_operand(&mut self,
     }
 
     pub fn trans_scalar_binop(&mut self,
-                              bcx: &BlockAndBuilder<'a, 'tcx>,
+                              bcx: &Builder<'a, 'tcx>,
                               op: mir::BinOp,
                               lhs: ValueRef,
                               rhs: ValueRef,
@@ -552,7 +558,7 @@ pub fn trans_scalar_binop(&mut self,
     }
 
     pub fn trans_fat_ptr_binop(&mut self,
-                               bcx: &BlockAndBuilder<'a, 'tcx>,
+                               bcx: &Builder<'a, 'tcx>,
                                op: mir::BinOp,
                                lhs_addr: ValueRef,
                                lhs_extra: ValueRef,
@@ -599,7 +605,7 @@ pub fn trans_fat_ptr_binop(&mut self,
     }
 
     pub fn trans_scalar_checked_binop(&mut self,
-                                      bcx: &BlockAndBuilder<'a, 'tcx>,
+                                      bcx: &Builder<'a, 'tcx>,
                                       op: mir::BinOp,
                                       lhs: ValueRef,
                                       rhs: ValueRef,
@@ -681,7 +687,7 @@ enum OverflowOp {
     Add, Sub, Mul
 }
 
-fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> ValueRef {
+fn get_overflow_intrinsic(oop: OverflowOp, bcx: &Builder, ty: Ty) -> ValueRef {
     use syntax::ast::IntTy::*;
     use syntax::ast::UintTy::*;
     use rustc::ty::{TyInt, TyUint};
index cc85f68c197ec34551df74a1742b7d171ddf5bc5..48fc9720e4b8317eb374fc1811499c0b048d8c62 100644 (file)
@@ -11,7 +11,8 @@
 use rustc::mir;
 
 use base;
-use common::{self, BlockAndBuilder};
+use common;
+use builder::Builder;
 
 use super::MirContext;
 use super::LocalRef;
@@ -20,9 +21,9 @@
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_statement(&mut self,
-                           bcx: BlockAndBuilder<'a, 'tcx>,
+                           bcx: Builder<'a, 'tcx>,
                            statement: &mir::Statement<'tcx>)
-                           -> BlockAndBuilder<'a, 'tcx> {
+                           -> Builder<'a, 'tcx> {
         debug!("trans_statement(statement={:?})", statement);
 
         self.set_debug_loc(&bcx, statement.source_info);
@@ -77,10 +78,10 @@ pub fn trans_statement(&mut self,
     }
 
     fn trans_storage_liveness(&self,
-                              bcx: BlockAndBuilder<'a, 'tcx>,
+                              bcx: Builder<'a, 'tcx>,
                               lvalue: &mir::Lvalue<'tcx>,
                               intrinsic: base::Lifetime)
-                              -> BlockAndBuilder<'a, 'tcx> {
+                              -> Builder<'a, 'tcx> {
         if let mir::Lvalue::Local(index) = *lvalue {
             if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
                 intrinsic.call(&bcx, tr_lval.llval);
index c09726fda081028c6d48b71d8f9cdecdcf6ad624..cbcbb02bdc89017ebb573ad6a9c06b57f2d94620 100644 (file)
@@ -9,28 +9,29 @@
 // except according to those terms.
 
 use llvm;
+use builder::Builder;
 use llvm::ValueRef;
 use common::*;
 use rustc::ty::Ty;
 
 pub fn slice_for_each<'a, 'tcx, F>(
-    bcx: &BlockAndBuilder<'a, 'tcx>,
+    bcx: &Builder<'a, 'tcx>,
     data_ptr: ValueRef,
     unit_ty: Ty<'tcx>,
     len: ValueRef,
     f: F
-) -> BlockAndBuilder<'a, 'tcx> where F: FnOnce(&BlockAndBuilder<'a, 'tcx>, ValueRef) {
+) -> Builder<'a, 'tcx> where F: FnOnce(&Builder<'a, 'tcx>, ValueRef) {
     // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
     let zst = type_is_zero_size(bcx.ccx, unit_ty);
-    let add = |bcx: &BlockAndBuilder, a, b| if zst {
+    let add = |bcx: &Builder, a, b| if zst {
         bcx.add(a, b)
     } else {
         bcx.inbounds_gep(a, &[b])
     };
 
-    let body_bcx = bcx.fcx().build_new_block("slice_loop_body");
-    let next_bcx = bcx.fcx().build_new_block("slice_loop_next");
-    let header_bcx = bcx.fcx().build_new_block("slice_loop_header");
+    let body_bcx = bcx.build_sibling_block("slice_loop_body");
+    let next_bcx = bcx.build_sibling_block("slice_loop_next");
+    let header_bcx = bcx.build_sibling_block("slice_loop_header");
 
     let start = if zst {
         C_uint(bcx.ccx, 0usize)
index 9b86196b3ece234b91eb760575bd23989362d14d..0fa9062df45915adb3fef479310a6907b56ccc69 100644 (file)
@@ -399,7 +399,13 @@ pub fn check_match(&self,
                 self.check_pat(&p, discrim_ty);
                 all_pats_diverge &= self.diverges.get();
             }
-            all_pats_diverge
+            // As discussed with @eddyb, this is for disabling unreachable_code
+            // warnings on patterns (they're now subsumed by unreachable_patterns
+            // warnings).
+            match all_pats_diverge {
+                Diverges::Maybe => Diverges::Maybe,
+                Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways,
+            }
         }).collect();
 
         // Now typecheck the blocks.
index 26dd53fecb243e306626a2ecd57ca7a2bf5ebb74..ec1ca99c7687f3af9c00aae4053c5e483643b5d2 100644 (file)
@@ -3552,19 +3552,23 @@ fn check_expr_kind(&self,
                     hir::UnNot => {
                         oprnd_t = self.structurally_resolved_type(oprnd.span,
                                                                   oprnd_t);
+                        let result = self.check_user_unop("!", "not",
+                                                          tcx.lang_items.not_trait(),
+                                                          expr, &oprnd, oprnd_t, unop);
+                        // If it's builtin, we can reuse the type, this helps inference.
                         if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
-                            oprnd_t = self.check_user_unop("!", "not",
-                                                           tcx.lang_items.not_trait(),
-                                                           expr, &oprnd, oprnd_t, unop);
+                            oprnd_t = result;
                         }
                     }
                     hir::UnNeg => {
                         oprnd_t = self.structurally_resolved_type(oprnd.span,
                                                                   oprnd_t);
+                        let result = self.check_user_unop("-", "neg",
+                                                          tcx.lang_items.neg_trait(),
+                                                          expr, &oprnd, oprnd_t, unop);
+                        // If it's builtin, we can reuse the type, this helps inference.
                         if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
-                            oprnd_t = self.check_user_unop("-", "neg",
-                                                           tcx.lang_items.neg_trait(),
-                                                           expr, &oprnd, oprnd_t, unop);
+                            oprnd_t = result;
                         }
                     }
                 }
index 9a2bfbf715af9785bb6432e24c9264dd63d65459..6d32b7364f8ea36aff3b3fb2b366cb756e1b6d05 100644 (file)
@@ -123,8 +123,17 @@ fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) {
     // as potentially overloaded. But then, during writeback, if
     // we observe that something like `a+b` is (known to be)
     // operating on scalars, we clear the overload.
-    fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
+    fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
         match e.node {
+            hir::ExprUnary(hir::UnNeg, ref inner) |
+            hir::ExprUnary(hir::UnNot, ref inner)  => {
+                let inner_ty = self.fcx.node_ty(inner.id);
+                let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
+
+                if inner_ty.is_scalar() {
+                    self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+                }
+            }
             hir::ExprBinary(ref op, ref lhs, ref rhs) |
             hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
                 let lhs_ty = self.fcx.node_ty(lhs.id);
@@ -185,7 +194,7 @@ fn visit_expr(&mut self, e: &'gcx hir::Expr) {
             return;
         }
 
-        self.fix_scalar_binary_expr(e);
+        self.fix_scalar_builtin_expr(e);
 
         self.visit_node_id(ResolvingExpr(e.span), e.id);
         self.visit_method_map_entry(ResolvingExpr(e.span),
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
new file mode 100644 (file)
index 0000000..ba95a17
--- /dev/null
@@ -0,0 +1,349 @@
+// 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.
+
+//! Check properties that are required by built-in traits and set
+//! up data structures required by type-checking/translation.
+
+use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::lang_items::UnsizeTraitLangItem;
+
+use rustc::traits::{self, ObligationCause, Reveal};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::ParameterEnvironment;
+use rustc::ty::TypeFoldable;
+use rustc::ty::subst::Subst;
+use rustc::ty::util::CopyImplementationError;
+use rustc::infer;
+
+use rustc::hir::def_id::DefId;
+use rustc::hir::map as hir_map;
+use rustc::hir::{self, ItemImpl};
+
+pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
+    check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
+    check_trait(
+        tcx,
+        tcx.lang_items.coerce_unsized_trait(),
+        visit_implementation_of_coerce_unsized);
+}
+
+fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            trait_def_id: Option<DefId>,
+                            mut f: F)
+    where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
+{
+    if let Some(trait_def_id) = trait_def_id {
+        let mut impls = vec![];
+        tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
+            impls.push(did);
+        });
+        impls.sort();
+        for impl_def_id in impls {
+            f(tcx, trait_def_id, impl_def_id);
+        }
+    }
+}
+
+fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                          _drop_did: DefId,
+                                          impl_did: DefId) {
+    let items = tcx.associated_item_def_ids(impl_did);
+    if items.is_empty() {
+        // We'll error out later. For now, just don't ICE.
+        return;
+    }
+    let method_def_id = items[0];
+
+    let self_type = tcx.item_type(impl_did);
+    match self_type.sty {
+        ty::TyAdt(type_def, _) => {
+            type_def.set_destructor(method_def_id);
+        }
+        _ => {
+            // Destructors only work on nominal types.
+            if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
+                match tcx.map.find(impl_node_id) {
+                    Some(hir_map::NodeItem(item)) => {
+                        let span = match item.node {
+                            ItemImpl(.., ref ty, _) => ty.span,
+                            _ => item.span,
+                        };
+                        struct_span_err!(tcx.sess,
+                                         span,
+                                         E0120,
+                                         "the Drop trait may only be implemented on \
+                                         structures")
+                            .span_label(span, &format!("implementing Drop requires a struct"))
+                            .emit();
+                    }
+                    _ => {
+                        bug!("didn't find impl in ast map");
+                    }
+                }
+            } else {
+                bug!("found external impl of Drop trait on \
+                      something other than a struct");
+            }
+        }
+    }
+}
+
+fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                          _copy_did: DefId,
+                                          impl_did: DefId) {
+    debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
+
+    let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+        n
+    } else {
+        debug!("visit_implementation_of_copy(): impl not in this \
+                crate");
+        return;
+    };
+
+    let self_type = tcx.item_type(impl_did);
+    debug!("visit_implementation_of_copy: self_type={:?} (bound)",
+           self_type);
+
+    let span = tcx.map.span(impl_node_id);
+    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+    let self_type = self_type.subst(tcx, &param_env.free_substs);
+    assert!(!self_type.has_escaping_regions());
+
+    debug!("visit_implementation_of_copy: self_type={:?} (free)",
+           self_type);
+
+    match param_env.can_type_implement_copy(tcx, self_type, span) {
+        Ok(()) => {}
+        Err(CopyImplementationError::InfrigingField(field)) => {
+            let item = tcx.map.expect_item(impl_node_id);
+            let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
+                tr.path.span
+            } else {
+                span
+            };
+
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0204,
+                             "the trait `Copy` may not be implemented for this type")
+                .span_label(
+                    tcx.def_span(field.did),
+                    &"this field does not implement `Copy`")
+                .emit()
+        }
+        Err(CopyImplementationError::NotAnAdt) => {
+            let item = tcx.map.expect_item(impl_node_id);
+            let span = if let ItemImpl(.., ref ty, _) = item.node {
+                ty.span
+            } else {
+                span
+            };
+
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0206,
+                             "the trait `Copy` may not be implemented for this type")
+                .span_label(span, &format!("type is not a structure or enumeration"))
+                .emit();
+        }
+        Err(CopyImplementationError::HasDestructor) => {
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0184,
+                             "the trait `Copy` may not be implemented for this type; the \
+                              type has a destructor")
+                .span_label(span, &format!("Copy not allowed on types with destructors"))
+                .emit();
+        }
+    }
+}
+
+fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                                    coerce_unsized_trait: DefId,
+                                                    impl_did: DefId) {
+    debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
+           impl_did);
+
+    let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
+        Ok(id) => id,
+        Err(err) => {
+            tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
+        }
+    };
+
+    let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+        n
+    } else {
+        debug!("visit_implementation_of_coerce_unsized(): impl not \
+                in this crate");
+        return;
+    };
+
+    let source = tcx.item_type(impl_did);
+    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+    let target = trait_ref.substs.type_at(1);
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
+           source,
+           target);
+
+    let span = tcx.map.span(impl_node_id);
+    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+    let source = source.subst(tcx, &param_env.free_substs);
+    let target = target.subst(tcx, &param_env.free_substs);
+    assert!(!source.has_escaping_regions());
+
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
+           source,
+           target);
+
+    tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
+        let cause = ObligationCause::misc(span, impl_node_id);
+        let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+                           mt_b: ty::TypeAndMut<'tcx>,
+                           mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
+            if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
+                infcx.report_mismatched_types(&cause,
+                                             mk_ptr(mt_b.ty),
+                                             target,
+                                             ty::error::TypeError::Mutability)
+                    .emit();
+            }
+            (mt_a.ty, mt_b.ty, unsize_trait, None)
+        };
+        let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
+            (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
+
+            (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
+                infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+            }
+
+            (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
+            (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+            }
+
+            (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) if def_a.is_struct() &&
+                                                                          def_b.is_struct() => {
+                if def_a != def_b {
+                    let source_path = tcx.item_path_str(def_a.did);
+                    let target_path = tcx.item_path_str(def_b.did);
+                    span_err!(tcx.sess,
+                              span,
+                              E0377,
+                              "the trait `CoerceUnsized` may only be implemented \
+                               for a coercion between structures with the same \
+                               definition; expected {}, found {}",
+                              source_path,
+                              target_path);
+                    return;
+                }
+
+                let fields = &def_a.struct_variant().fields;
+                let diff_fields = fields.iter()
+                    .enumerate()
+                    .filter_map(|(i, f)| {
+                        let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+                        if tcx.item_type(f.did).is_phantom_data() {
+                            // Ignore PhantomData fields
+                            return None;
+                        }
+
+                        // Ignore fields that aren't significantly changed
+                        if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
+                            if ok.obligations.is_empty() {
+                                return None;
+                            }
+                        }
+
+                        // Collect up all fields that were significantly changed
+                        // i.e. those that contain T in coerce_unsized T -> U
+                        Some((i, a, b))
+                    })
+                    .collect::<Vec<_>>();
+
+                if diff_fields.is_empty() {
+                    span_err!(tcx.sess,
+                              span,
+                              E0374,
+                              "the trait `CoerceUnsized` may only be implemented \
+                               for a coercion between structures with one field \
+                               being coerced, none found");
+                    return;
+                } else if diff_fields.len() > 1 {
+                    let item = tcx.map.expect_item(impl_node_id);
+                    let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
+                        t.path.span
+                    } else {
+                        tcx.map.span(impl_node_id)
+                    };
+
+                    let mut err = struct_span_err!(tcx.sess,
+                                                   span,
+                                                   E0375,
+                                                   "implementing the trait \
+                                                    `CoerceUnsized` requires multiple \
+                                                    coercions");
+                    err.note("`CoerceUnsized` may only be implemented for \
+                              a coercion between structures with one field being coerced");
+                    err.note(&format!("currently, {} fields need coercions: {}",
+                                      diff_fields.len(),
+                                      diff_fields.iter()
+                                          .map(|&(i, a, b)| {
+                                              format!("{} ({} to {})", fields[i].name, a, b)
+                                          })
+                                          .collect::<Vec<_>>()
+                                          .join(", ")));
+                    err.span_label(span, &format!("requires multiple coercions"));
+                    err.emit();
+                    return;
+                }
+
+                let (i, a, b) = diff_fields[0];
+                let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+                (a, b, coerce_unsized_trait, Some(kind))
+            }
+
+            _ => {
+                span_err!(tcx.sess,
+                          span,
+                          E0376,
+                          "the trait `CoerceUnsized` may only be implemented \
+                           for a coercion between structures");
+                return;
+            }
+        };
+
+        let mut fulfill_cx = traits::FulfillmentContext::new();
+
+        // Register an obligation for `A: Trait<B>`.
+        let cause = traits::ObligationCause::misc(span, impl_node_id);
+        let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
+        fulfill_cx.register_predicate_obligation(&infcx, predicate);
+
+        // Check that all transitive obligations are satisfied.
+        if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(&errors);
+        }
+
+        // Finally, resolve all regions.
+        let mut free_regions = FreeRegionMap::new();
+        free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
+            .caller_bounds);
+        infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
+
+        if let Some(kind) = kind {
+            tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+        }
+    });
+}
index 3bbe5aa1fef376272fd19e28e1f57ae5f4b741ae..6cf752dd69fcadea7d82f05ab89999e0c817c87a 100644 (file)
 // mappings. That mapping code resides here.
 
 use hir::def_id::DefId;
-use middle::lang_items::UnsizeTraitLangItem;
-use rustc::ty::subst::Subst;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc::traits::{self, ObligationCause, Reveal};
-use rustc::ty::ParameterEnvironment;
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
 use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
 use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use rustc::ty::{TyProjection, TyAnon};
-use rustc::ty::util::CopyImplementationError;
-use middle::free_region::FreeRegionMap;
 use CrateCtxt;
-use rustc::infer::{self, InferCtxt};
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
-use rustc::hir::map as hir_map;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{Item, ItemImpl};
 use rustc::hir;
 
+mod builtin;
 mod orphan;
 mod overlap;
 mod unsafety;
 
-struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    crate_context: &'a CrateCtxt<'a, 'gcx>,
-    inference_context: InferCtxt<'a, 'gcx, 'tcx>,
+struct CoherenceChecker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
-}
-
-impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceChecker<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
-            self.cc.check_implementation(item)
+            self.check_implementation(item)
         }
     }
 
@@ -65,7 +53,7 @@ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
 
-impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
     // Returns the def ID of the base type, if there is one.
     fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
         match ty.sty {
@@ -73,7 +61,7 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
 
             TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
 
-            TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
+            TyBox(_) => self.tcx.lang_items.owned_box(),
 
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
             TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
@@ -89,36 +77,22 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
         }
     }
 
-    fn check(&self) {
+    fn check(&mut self) {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        self.crate_context.tcx.visit_all_item_likes_in_krate(
-            DepNode::CoherenceCheckImpl,
-            &mut CoherenceCheckVisitor { cc: self });
-
-        // Populate the table of destructors. It might seem a bit strange to
-        // do this here, but it's actually the most convenient place, since
-        // the coherence tables contain the trait -> type mappings.
-        self.populate_destructors();
-
-        // Check to make sure implementations of `Copy` are legal.
-        self.check_implementations_of_copy();
-
-        // Check to make sure implementations of `CoerceUnsized` are legal
-        // and collect the necessary information from them.
-        self.check_implementations_of_coerce_unsized();
+        self.tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, self);
     }
 
     fn check_implementation(&self, item: &Item) {
-        let tcx = self.crate_context.tcx;
+        let tcx = self.tcx;
         let impl_did = tcx.map.local_def_id(item.id);
         let self_type = tcx.item_type(impl_did);
 
         // If there are no traits, then this implementation must have a
         // base type.
 
-        if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
+        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
             debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
                    trait_ref,
                    item.name);
@@ -129,9 +103,7 @@ fn check_implementation(&self, item: &Item) {
                 return;
             }
 
-            enforce_trait_manually_implementable(self.crate_context.tcx,
-                                                 item.span,
-                                                 trait_ref.def_id);
+            enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
             self.add_trait_impl(trait_ref, impl_did);
         } else {
             // Skip inherent impls where the self type is an error
@@ -150,348 +122,15 @@ fn check_implementation(&self, item: &Item) {
     }
 
     fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
-        let tcx = self.crate_context.tcx;
-        tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
+        self.tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
     }
 
-    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
+    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
                impl_trait_ref,
                impl_def_id);
-        let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
-        trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
-    }
-
-    // Destructors
-    //
-
-    fn populate_destructors(&self) {
-        let tcx = self.crate_context.tcx;
-        let drop_trait = match tcx.lang_items.drop_trait() {
-            Some(id) => id,
-            None => return,
-        };
-        tcx.populate_implementations_for_trait_if_necessary(drop_trait);
-        let drop_trait = tcx.lookup_trait_def(drop_trait);
-
-        drop_trait.for_each_impl(tcx, |impl_did| {
-            let items = tcx.associated_item_def_ids(impl_did);
-            if items.is_empty() {
-                // We'll error out later. For now, just don't ICE.
-                return;
-            }
-            let method_def_id = items[0];
-
-            let self_type = tcx.item_type(impl_did);
-            match self_type.sty {
-                ty::TyAdt(type_def, _) => {
-                    type_def.set_destructor(method_def_id);
-                }
-                _ => {
-                    // Destructors only work on nominal types.
-                    if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
-                        match tcx.map.find(impl_node_id) {
-                            Some(hir_map::NodeItem(item)) => {
-                                let span = match item.node {
-                                    ItemImpl(.., ref ty, _) => ty.span,
-                                    _ => item.span,
-                                };
-                                struct_span_err!(tcx.sess,
-                                                 span,
-                                                 E0120,
-                                                 "the Drop trait may only be implemented on \
-                                                  structures")
-                                    .span_label(span,
-                                                &format!("implementing Drop requires a struct"))
-                                    .emit();
-                            }
-                            _ => {
-                                bug!("didn't find impl in ast map");
-                            }
-                        }
-                    } else {
-                        bug!("found external impl of Drop trait on \
-                              something other than a struct");
-                    }
-                }
-            }
-        });
-    }
-
-    /// Ensures that implementations of the built-in trait `Copy` are legal.
-    fn check_implementations_of_copy(&self) {
-        let tcx = self.crate_context.tcx;
-        let copy_trait = match tcx.lang_items.copy_trait() {
-            Some(id) => id,
-            None => return,
-        };
-        tcx.populate_implementations_for_trait_if_necessary(copy_trait);
-        let copy_trait = tcx.lookup_trait_def(copy_trait);
-
-        copy_trait.for_each_impl(tcx, |impl_did| {
-            debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
-
-            let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
-                n
-            } else {
-                debug!("check_implementations_of_copy(): impl not in this \
-                        crate");
-                return;
-            };
-
-            let self_type = tcx.item_type(impl_did);
-            debug!("check_implementations_of_copy: self_type={:?} (bound)",
-                   self_type);
-
-            let span = tcx.map.span(impl_node_id);
-            let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-            let self_type = self_type.subst(tcx, &param_env.free_substs);
-            assert!(!self_type.has_escaping_regions());
-
-            debug!("check_implementations_of_copy: self_type={:?} (free)",
-                   self_type);
-
-            match param_env.can_type_implement_copy(tcx, self_type, span) {
-                Ok(()) => {}
-                Err(CopyImplementationError::InfrigingField(name)) => {
-                    struct_span_err!(tcx.sess,
-                                     span,
-                                     E0204,
-                                     "the trait `Copy` may not be implemented for this type")
-                        .span_label(span, &format!("field `{}` does not implement `Copy`", name))
-                        .emit()
-                }
-                Err(CopyImplementationError::InfrigingVariant(name)) => {
-                    let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
-                        tr.path.span
-                    } else {
-                        span
-                    };
-
-                    struct_span_err!(tcx.sess,
-                                     span,
-                                     E0205,
-                                     "the trait `Copy` may not be implemented for this type")
-                        .span_label(span,
-                                    &format!("variant `{}` does not implement `Copy`", name))
-                        .emit()
-                }
-                Err(CopyImplementationError::NotAnAdt) => {
-                    let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(.., ref ty, _) = item.node {
-                        ty.span
-                    } else {
-                        span
-                    };
-
-                    struct_span_err!(tcx.sess,
-                                     span,
-                                     E0206,
-                                     "the trait `Copy` may not be implemented for this type")
-                        .span_label(span, &format!("type is not a structure or enumeration"))
-                        .emit();
-                }
-                Err(CopyImplementationError::HasDestructor) => {
-                    struct_span_err!(tcx.sess,
-                                     span,
-                                     E0184,
-                                     "the trait `Copy` may not be implemented for this type; the \
-                                      type has a destructor")
-                        .span_label(span, &format!("Copy not allowed on types with destructors"))
-                        .emit();
-                }
-            }
-        });
-    }
-
-    /// Process implementations of the built-in trait `CoerceUnsized`.
-    fn check_implementations_of_coerce_unsized(&self) {
-        let tcx = self.crate_context.tcx;
-        let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
-            Some(id) => id,
-            None => return,
-        };
-        let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
-            Ok(id) => id,
-            Err(err) => {
-                tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
-            }
-        };
-
-        let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
-
-        trait_def.for_each_impl(tcx, |impl_did| {
-            debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
-                   impl_did);
-
-            let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
-                n
-            } else {
-                debug!("check_implementations_of_coerce_unsized(): impl not \
-                        in this crate");
-                return;
-            };
-
-            let source = tcx.item_type(impl_did);
-            let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
-            let target = trait_ref.substs.type_at(1);
-            debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
-                   source,
-                   target);
-
-            let span = tcx.map.span(impl_node_id);
-            let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-            let source = source.subst(tcx, &param_env.free_substs);
-            let target = target.subst(tcx, &param_env.free_substs);
-            assert!(!source.has_escaping_regions());
-
-            debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
-                   source,
-                   target);
-
-            tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
-                let cause = ObligationCause::misc(span, impl_node_id);
-                let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
-                                   mt_b: ty::TypeAndMut<'gcx>,
-                                   mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
-                    if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
-                        infcx.report_mismatched_types(&cause,
-                                                      mk_ptr(mt_b.ty),
-                                                      target,
-                                                      ty::error::TypeError::Mutability).emit();
-                    }
-                    (mt_a.ty, mt_b.ty, unsize_trait, None)
-                };
-                let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
-                    (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
-
-                    (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
-                        infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
-                        check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
-                    }
-
-                    (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
-                    (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
-                        check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
-                    }
-
-                    (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
-                        if def_a.is_struct() && def_b.is_struct() => {
-                        if def_a != def_b {
-                            let source_path = tcx.item_path_str(def_a.did);
-                            let target_path = tcx.item_path_str(def_b.did);
-                            span_err!(tcx.sess,
-                                      span,
-                                      E0377,
-                                      "the trait `CoerceUnsized` may only be implemented \
-                                       for a coercion between structures with the same \
-                                       definition; expected {}, found {}",
-                                      source_path,
-                                      target_path);
-                            return;
-                        }
-
-                        let fields = &def_a.struct_variant().fields;
-                        let diff_fields = fields.iter()
-                            .enumerate()
-                            .filter_map(|(i, f)| {
-                                let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
-                                if tcx.item_type(f.did).is_phantom_data() {
-                                    // Ignore PhantomData fields
-                                    return None;
-                                }
-
-                                // Ignore fields that aren't significantly changed
-                                if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
-                                    if ok.obligations.is_empty() {
-                                        return None;
-                                    }
-                                }
-
-                                // Collect up all fields that were significantly changed
-                                // i.e. those that contain T in coerce_unsized T -> U
-                                Some((i, a, b))
-                            })
-                            .collect::<Vec<_>>();
-
-                        if diff_fields.is_empty() {
-                            span_err!(tcx.sess,
-                                      span,
-                                      E0374,
-                                      "the trait `CoerceUnsized` may only be implemented \
-                                       for a coercion between structures with one field \
-                                       being coerced, none found");
-                            return;
-                        } else if diff_fields.len() > 1 {
-                            let item = tcx.map.expect_item(impl_node_id);
-                            let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
-                                t.path.span
-                            } else {
-                                tcx.map.span(impl_node_id)
-                            };
-
-                            let mut err = struct_span_err!(tcx.sess,
-                                                           span,
-                                                           E0375,
-                                                           "implementing the trait \
-                                                            `CoerceUnsized` requires multiple \
-                                                            coercions");
-                            err.note("`CoerceUnsized` may only be implemented for \
-                                      a coercion between structures with one field being coerced");
-                            err.note(&format!("currently, {} fields need coercions: {}",
-                                              diff_fields.len(),
-                                              diff_fields.iter()
-                                                  .map(|&(i, a, b)| {
-                                                      format!("{} ({} to {})", fields[i].name, a, b)
-                                                  })
-                                                  .collect::<Vec<_>>()
-                                                  .join(", ")));
-                            err.span_label(span, &format!("requires multiple coercions"));
-                            err.emit();
-                            return;
-                        }
-
-                        let (i, a, b) = diff_fields[0];
-                        let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
-                        (a, b, coerce_unsized_trait, Some(kind))
-                    }
-
-                    _ => {
-                        span_err!(tcx.sess,
-                                  span,
-                                  E0376,
-                                  "the trait `CoerceUnsized` may only be implemented \
-                                   for a coercion between structures");
-                        return;
-                    }
-                };
-
-                let mut fulfill_cx = traits::FulfillmentContext::new();
-
-                // Register an obligation for `A: Trait<B>`.
-                let cause = traits::ObligationCause::misc(span, impl_node_id);
-                let predicate =
-                    tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
-                fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
-                // Check that all transitive obligations are satisfied.
-                if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&errors);
-                }
-
-                // Finally, resolve all regions.
-                let mut free_regions = FreeRegionMap::new();
-                free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
-                    .caller_bounds);
-                infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
-
-                if let Some(kind) = kind {
-                    tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
-                }
-            });
-        });
+        let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
+        trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
     }
 }
 
@@ -524,14 +163,9 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
 
 pub fn check_coherence(ccx: &CrateCtxt) {
     let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
-    ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
-        CoherenceChecker {
-                crate_context: ccx,
-                inference_context: infcx,
-            }
-            .check();
-    });
+    CoherenceChecker { tcx: ccx.tcx }.check();
     unsafety::check(ccx.tcx);
     orphan::check(ccx.tcx);
     overlap::check(ccx.tcx);
+    builtin::check(ccx.tcx);
 }
index d3b671f2a4d6e05ee026dd921176c9cbb4bf6ae8..1a971be64d81923d528313df3b01b0d892c7f251 100644 (file)
@@ -2300,6 +2300,7 @@ struct Foo<'a> {
 differs from the behavior for `&T`, which is always `Copy`).
 "##,
 
+/*
 E0205: r##"
 An attempt to implement the `Copy` trait for an enum failed because one of the
 variants does not implement `Copy`. To fix this, you must implement `Copy` for
@@ -2329,6 +2330,7 @@ enum Foo<'a> {
 This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
 differs from the behavior for `&T`, which is always `Copy`).
 "##,
+*/
 
 E0206: r##"
 You can only implement `Copy` for a struct or enum. Both of the following
index e0a26ca318189e8226374a2f37f4e3761c8428c0..faf39db572380feca0554b5d49bfb9c00a2829ed 100644 (file)
@@ -2219,8 +2219,8 @@ pub fn singleton(name: String) -> Path {
         }
     }
 
-    pub fn last_name(&self) -> String {
-        self.segments.last().unwrap().name.clone()
+    pub fn last_name(&self) -> &str {
+        self.segments.last().unwrap().name.as_str()
     }
 }
 
index 1f989c557d3aa7140be362292e6c6bfd01358942..514eb6ea843defc4d24b501278b3118d568145ff 100644 (file)
@@ -156,9 +156,15 @@ pub fn run_core(search_paths: SearchPaths,
     let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);
 
     let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
-        driver::phase_2_configure_and_expand(
-            &sess, &cstore, krate, None, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
-        ).expect("phase_2_configure_and_expand aborted in rustdoc!")
+        let result = driver::phase_2_configure_and_expand(&sess,
+                                                          &cstore,
+                                                          krate,
+                                                          None,
+                                                          &name,
+                                                          None,
+                                                          resolve::MakeGlobMap::No,
+                                                          |_| Ok(()));
+        abort_on_err(result, &sess)
     };
 
     let arena = DroplessArena::new();
index 796a3a93068c8a5d8886a39b83057594ffdce949..716ad05401d03036a459da76f97ccdcc89ab4f3b 100644 (file)
@@ -433,7 +433,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
 /// rendering function with the necessary arguments for linking to a local path.
 fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
-                 print_all: bool) -> fmt::Result {
+                 print_all: bool, use_absolute: bool) -> fmt::Result {
     let last = path.segments.last().unwrap();
     let rel_root = match &*path.segments[0].name {
         "self" => Some("./".to_string()),
@@ -467,7 +467,17 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
     if w.alternate() {
         write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
     } else {
-        write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
+        let path = if use_absolute {
+            match href(did) {
+                Some((_, _, fqp)) => format!("{}::{}",
+                                             fqp[..fqp.len()-1].join("::"),
+                                             HRef::new(did, fqp.last().unwrap())),
+                None => format!("{}", HRef::new(did, &last.name)),
+            }
+        } else {
+            format!("{}", HRef::new(did, &last.name))
+        };
+        write!(w, "{}{}", path, last.params)?;
     }
     Ok(())
 }
@@ -551,194 +561,201 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Display for clean::Type {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            clean::Generic(ref name) => {
-                f.write_str(name)
-            }
-            clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
-                // Paths like T::Output and Self::Output should be rendered with all segments
-                resolved_path(f, did, path, is_generic)?;
-                tybounds(f, typarams)
+fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
+    match *t {
+        clean::Generic(ref name) => {
+            f.write_str(name)
+        }
+        clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
+            // Paths like T::Output and Self::Output should be rendered with all segments
+            resolved_path(f, did, path, is_generic, use_absolute)?;
+            tybounds(f, typarams)
+        }
+        clean::Infer => write!(f, "_"),
+        clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
+        clean::BareFunction(ref decl) => {
+            if f.alternate() {
+                write!(f, "{}{}fn{:#}{:#}",
+                       UnsafetySpace(decl.unsafety),
+                       AbiSpace(decl.abi),
+                       decl.generics,
+                       decl.decl)
+            } else {
+                write!(f, "{}{}fn{}{}",
+                       UnsafetySpace(decl.unsafety),
+                       AbiSpace(decl.abi),
+                       decl.generics,
+                       decl.decl)
             }
-            clean::Infer => write!(f, "_"),
-            clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
-            clean::BareFunction(ref decl) => {
-                if f.alternate() {
-                    write!(f, "{}{}fn{:#}{:#}",
-                           UnsafetySpace(decl.unsafety),
-                           AbiSpace(decl.abi),
-                           decl.generics,
-                           decl.decl)
-                } else {
-                    write!(f, "{}{}fn{}{}",
-                           UnsafetySpace(decl.unsafety),
-                           AbiSpace(decl.abi),
-                           decl.generics,
-                           decl.decl)
+        }
+        clean::Tuple(ref typs) => {
+            match &typs[..] {
+                &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
+                &[ref one] => {
+                    primitive_link(f, PrimitiveType::Tuple, "(")?;
+                    //carry f.alternate() into this display w/o branching manually
+                    fmt::Display::fmt(one, f)?;
+                    primitive_link(f, PrimitiveType::Tuple, ",)")
                 }
-            }
-            clean::Tuple(ref typs) => {
-                match &typs[..] {
-                    &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
-                    &[ref one] => {
-                        primitive_link(f, PrimitiveType::Tuple, "(")?;
-                        //carry f.alternate() into this display w/o branching manually
-                        fmt::Display::fmt(one, f)?;
-                        primitive_link(f, PrimitiveType::Tuple, ",)")
-                    }
-                    many => {
-                        primitive_link(f, PrimitiveType::Tuple, "(")?;
-                        fmt::Display::fmt(&CommaSep(&many), f)?;
-                        primitive_link(f, PrimitiveType::Tuple, ")")
-                    }
+                many => {
+                    primitive_link(f, PrimitiveType::Tuple, "(")?;
+                    fmt::Display::fmt(&CommaSep(&many), f)?;
+                    primitive_link(f, PrimitiveType::Tuple, ")")
                 }
             }
-            clean::Vector(ref t) => {
-                primitive_link(f, PrimitiveType::Slice, &format!("["))?;
-                fmt::Display::fmt(t, f)?;
-                primitive_link(f, PrimitiveType::Slice, &format!("]"))
-            }
-            clean::FixedVector(ref t, ref s) => {
-                primitive_link(f, PrimitiveType::Array, "[")?;
-                fmt::Display::fmt(t, f)?;
-                if f.alternate() {
-                    primitive_link(f, PrimitiveType::Array,
-                                   &format!("; {}]", s))
-                } else {
-                    primitive_link(f, PrimitiveType::Array,
-                                   &format!("; {}]", Escape(s)))
-                }
+        }
+        clean::Vector(ref t) => {
+            primitive_link(f, PrimitiveType::Slice, &format!("["))?;
+            fmt::Display::fmt(t, f)?;
+            primitive_link(f, PrimitiveType::Slice, &format!("]"))
+        }
+        clean::FixedVector(ref t, ref s) => {
+            primitive_link(f, PrimitiveType::Array, "[")?;
+            fmt::Display::fmt(t, f)?;
+            if f.alternate() {
+                primitive_link(f, PrimitiveType::Array,
+                               &format!("; {}]", s))
+            } else {
+                primitive_link(f, PrimitiveType::Array,
+                               &format!("; {}]", Escape(s)))
             }
-            clean::Never => f.write_str("!"),
-            clean::RawPointer(m, ref t) => {
-                match **t {
-                    clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
-                        if f.alternate() {
-                            primitive_link(f, clean::PrimitiveType::RawPointer,
-                                           &format!("*{}{:#}", RawMutableSpace(m), t))
-                        } else {
-                            primitive_link(f, clean::PrimitiveType::RawPointer,
-                                           &format!("*{}{}", RawMutableSpace(m), t))
-                        }
-                    }
-                    _ => {
+        }
+        clean::Never => f.write_str("!"),
+        clean::RawPointer(m, ref t) => {
+            match **t {
+                clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
+                    if f.alternate() {
                         primitive_link(f, clean::PrimitiveType::RawPointer,
-                                       &format!("*{}", RawMutableSpace(m)))?;
-                        fmt::Display::fmt(t, f)
+                                       &format!("*{}{:#}", RawMutableSpace(m), t))
+                    } else {
+                        primitive_link(f, clean::PrimitiveType::RawPointer,
+                                       &format!("*{}{}", RawMutableSpace(m), t))
                     }
                 }
+                _ => {
+                    primitive_link(f, clean::PrimitiveType::RawPointer,
+                                   &format!("*{}", RawMutableSpace(m)))?;
+                    fmt::Display::fmt(t, f)
+                }
             }
-            clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
-                let lt = match *l {
-                    Some(ref l) => format!("{} ", *l),
-                    _ => "".to_string(),
-                };
-                let m = MutableSpace(mutability);
-                match **ty {
-                    clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
-                        match **bt {
-                            clean::Generic(_) =>
-                                if f.alternate() {
-                                    primitive_link(f, PrimitiveType::Slice,
-                                        &format!("&{}{}[{:#}]", lt, m, **bt))
-                                } else {
-                                    primitive_link(f, PrimitiveType::Slice,
-                                        &format!("&amp;{}{}[{}]", lt, m, **bt))
-                                },
-                            _ => {
-                                if f.alternate() {
-                                    primitive_link(f, PrimitiveType::Slice,
-                                                   &format!("&{}{}[", lt, m))?;
-                                    write!(f, "{:#}", **bt)?;
-                                } else {
-                                    primitive_link(f, PrimitiveType::Slice,
-                                                   &format!("&amp;{}{}[", lt, m))?;
-                                    write!(f, "{}", **bt)?;
-                                }
-                                primitive_link(f, PrimitiveType::Slice, "]")
+        }
+        clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
+            let lt = match *l {
+                Some(ref l) => format!("{} ", *l),
+                _ => "".to_string(),
+            };
+            let m = MutableSpace(mutability);
+            match **ty {
+                clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
+                    match **bt {
+                        clean::Generic(_) =>
+                            if f.alternate() {
+                                primitive_link(f, PrimitiveType::Slice,
+                                    &format!("&{}{}[{:#}]", lt, m, **bt))
+                            } else {
+                                primitive_link(f, PrimitiveType::Slice,
+                                    &format!("&amp;{}{}[{}]", lt, m, **bt))
+                            },
+                        _ => {
+                            if f.alternate() {
+                                primitive_link(f, PrimitiveType::Slice,
+                                               &format!("&{}{}[", lt, m))?;
+                                write!(f, "{:#}", **bt)?;
+                            } else {
+                                primitive_link(f, PrimitiveType::Slice,
+                                               &format!("&amp;{}{}[", lt, m))?;
+                                write!(f, "{}", **bt)?;
                             }
-                        }
-                    }
-                    _ => {
-                        if f.alternate() {
-                            write!(f, "&{}{}{:#}", lt, m, **ty)
-                        } else {
-                            write!(f, "&amp;{}{}{}", lt, m, **ty)
+                            primitive_link(f, PrimitiveType::Slice, "]")
                         }
                     }
                 }
-            }
-            clean::PolyTraitRef(ref bounds) => {
-                for (i, bound) in bounds.iter().enumerate() {
-                    if i != 0 {
-                        write!(f, " + ")?;
-                    }
+                _ => {
                     if f.alternate() {
-                        write!(f, "{:#}", *bound)?;
+                        write!(f, "&{}{}{:#}", lt, m, **ty)
                     } else {
-                        write!(f, "{}", *bound)?;
+                        write!(f, "&amp;{}{}{}", lt, m, **ty)
                     }
                 }
-                Ok(())
             }
-            clean::ImplTrait(ref bounds) => {
-                write!(f, "impl ")?;
-                for (i, bound) in bounds.iter().enumerate() {
-                    if i != 0 {
-                        write!(f, " + ")?;
-                    }
-                    if f.alternate() {
-                        write!(f, "{:#}", *bound)?;
-                    } else {
-                        write!(f, "{}", *bound)?;
-                    }
+        }
+        clean::PolyTraitRef(ref bounds) => {
+            for (i, bound) in bounds.iter().enumerate() {
+                if i != 0 {
+                    write!(f, " + ")?;
                 }
-                Ok(())
-            }
-            // It's pretty unsightly to look at `<A as B>::C` in output, and
-            // we've got hyperlinking on our side, so try to avoid longer
-            // notation as much as possible by making `C` a hyperlink to trait
-            // `B` to disambiguate.
-            //
-            // FIXME: this is still a lossy conversion and there should probably
-            //        be a better way of representing this in general? Most of
-            //        the ugliness comes from inlining across crates where
-            //        everything comes in as a fully resolved QPath (hard to
-            //        look at).
-            clean::QPath {
-                ref name,
-                ref self_type,
-                trait_: box clean::ResolvedPath { did, ref typarams, .. },
-            } => {
                 if f.alternate() {
-                    write!(f, "{:#}::", self_type)?;
+                    write!(f, "{:#}", *bound)?;
                 } else {
-                    write!(f, "{}::", self_type)?;
+                    write!(f, "{}", *bound)?;
                 }
-                let path = clean::Path::singleton(name.clone());
-                resolved_path(f, did, &path, false)?;
-
-                // FIXME: `typarams` are not rendered, and this seems bad?
-                drop(typarams);
-                Ok(())
             }
-            clean::QPath { ref name, ref self_type, ref trait_ } => {
+            Ok(())
+        }
+        clean::ImplTrait(ref bounds) => {
+            write!(f, "impl ")?;
+            for (i, bound) in bounds.iter().enumerate() {
+                if i != 0 {
+                    write!(f, " + ")?;
+                }
                 if f.alternate() {
-                    write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+                    write!(f, "{:#}", *bound)?;
                 } else {
-                    write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
+                    write!(f, "{}", *bound)?;
                 }
             }
-            clean::Unique(..) => {
-                panic!("should have been cleaned")
+            Ok(())
+        }
+        // It's pretty unsightly to look at `<A as B>::C` in output, and
+        // we've got hyperlinking on our side, so try to avoid longer
+        // notation as much as possible by making `C` a hyperlink to trait
+        // `B` to disambiguate.
+        //
+        // FIXME: this is still a lossy conversion and there should probably
+        //        be a better way of representing this in general? Most of
+        //        the ugliness comes from inlining across crates where
+        //        everything comes in as a fully resolved QPath (hard to
+        //        look at).
+        clean::QPath {
+            ref name,
+            ref self_type,
+            trait_: box clean::ResolvedPath { did, ref typarams, .. },
+        } => {
+            if f.alternate() {
+                write!(f, "{:#}::", self_type)?;
+            } else {
+                write!(f, "{}::", self_type)?;
+            }
+            let path = clean::Path::singleton(name.clone());
+            resolved_path(f, did, &path, true, use_absolute)?;
+
+            // FIXME: `typarams` are not rendered, and this seems bad?
+            drop(typarams);
+            Ok(())
+        }
+        clean::QPath { ref name, ref self_type, ref trait_ } => {
+            if f.alternate() {
+                write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+            } else {
+                write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
             }
         }
+        clean::Unique(..) => {
+            panic!("should have been cleaned")
+        }
+    }
+}
+
+impl fmt::Display for clean::Type {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt_type(self, f, false)
     }
 }
 
-fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result {
+fn fmt_impl(i: &clean::Impl,
+            f: &mut fmt::Formatter,
+            link_trait: bool,
+            use_absolute: bool) -> fmt::Result {
     let mut plain = String::new();
 
     if f.alternate() {
@@ -759,7 +776,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
             plain.push_str(&format!("{:#}", ty));
         } else {
             match *ty {
-                clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => {
+                clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
                     let last = path.segments.last().unwrap();
                     fmt::Display::fmt(&last.name, f)?;
                     fmt::Display::fmt(&last.params, f)?;
@@ -772,7 +789,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
         plain.push_str(" for ");
     }
 
-    fmt::Display::fmt(&i.for_, f)?;
+    fmt_type(&i.for_, f, use_absolute)?;
     plain.push_str(&format!("{:#}", i.for_));
 
     fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
@@ -781,13 +798,15 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
 
 impl fmt::Display for clean::Impl {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt_impl(self, f, true)
+        fmt_impl(self, f, true, false)
     }
 }
 
 // The difference from above is that trait is not hyperlinked.
-pub fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut fmt::Formatter) -> fmt::Result {
-    fmt_impl(i, f, false)
+pub fn fmt_impl_for_trait_page(i: &clean::Impl,
+                               f: &mut fmt::Formatter,
+                               use_absolute: bool) -> fmt::Result {
+    fmt_impl(i, f, false, use_absolute)
 }
 
 impl fmt::Display for clean::Arguments {
@@ -978,7 +997,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Display for clean::ImportSource {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.did {
-            Some(did) => resolved_path(f, did, &self.path, true),
+            Some(did) => resolved_path(f, did, &self.path, true, false),
             _ => {
                 for (i, seg) in self.path.segments.iter().enumerate() {
                     if i > 0 {
index ff7133f5d0c971efec75047d85e6e961eb1a5c19..9ea4bc436bfb83b08b4579bb209459cc8cdf531d 100644 (file)
@@ -2122,9 +2122,25 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
         <ul class='item-list' id='implementors-list'>
     ")?;
     if let Some(implementors) = cache.implementors.get(&it.def_id) {
-        for i in implementors {
+        let mut implementor_count: FxHashMap<&str, usize> = FxHashMap();
+        for implementor in implementors {
+            if let clean::Type::ResolvedPath {ref path, ..} = implementor.impl_.for_ {
+                *implementor_count.entry(path.last_name()).or_insert(0) += 1;
+            }
+        }
+
+        for implementor in implementors {
             write!(w, "<li><code>")?;
-            fmt_impl_for_trait_page(&i.impl_, w)?;
+            // If there's already another implementor that has the same abbridged name, use the
+            // full path, for example in `std::iter::ExactSizeIterator`
+            let use_absolute = if let clean::Type::ResolvedPath {
+                ref path, ..
+            } = implementor.impl_.for_ {
+                implementor_count[path.last_name()] > 1
+            } else {
+                false
+            };
+            fmt_impl_for_trait_page(&implementor.impl_, w, use_absolute)?;
             writeln!(w, "</code></li>")?;
         }
     }
index 63817c9f10f5fbb19892e61759b8e0f30f7858a5..ed1f08f9c90900c4164cc9e803078502d2a885ab 100644 (file)
@@ -613,44 +613,18 @@ pub fn ttl(&self) -> io::Result<u32> {
         self.0.ttl()
     }
 
-    /// Sets the value for the `IPV6_V6ONLY` option on this socket.
-    ///
-    /// If this is set to `true` then the socket is restricted to sending and
-    /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
-    /// can bind the same port at the same time.
-    ///
-    /// If this is set to `false` then the socket can be used to send and
-    /// receive packets from an IPv4-mapped IPv6 address.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::net::TcpListener;
-    ///
-    /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
-    /// listener.set_only_v6(true).expect("Cannot set to IPv6");
-    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
+    #[rustc_deprecated(since = "1.16.0",
+                       reason = "this option can only be set before the socket is bound")]
+    #[allow(missing_docs)]
     pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
         self.0.set_only_v6(only_v6)
     }
 
-    /// Gets the value of the `IPV6_V6ONLY` option for this socket.
-    ///
-    /// For more information about this option, see [`set_only_v6`][link].
-    ///
-    /// [link]: #method.set_only_v6
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::net::TcpListener;
-    ///
-    /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
-    /// listener.set_only_v6(true).expect("Cannot set to IPv6");
-    /// assert_eq!(listener.only_v6().unwrap_or(false), true);
-    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
+    #[rustc_deprecated(since = "1.16.0",
+                       reason = "this option can only be set before the socket is bound")]
+    #[allow(missing_docs)]
     pub fn only_v6(&self) -> io::Result<bool> {
         self.0.only_v6()
     }
index 3fdf61cfed83c22cfd24c77f9d0b2109e4fd1c49..0291d7f0e927a7d3fc03c85b7f24b95dcafaa865 100644 (file)
@@ -15,7 +15,7 @@
 use str::FromStr;
 use string::{String, ToString};
 use sys::syscall::EINVAL;
-use time;
+use time::{self, Duration};
 use vec::{IntoIter, Vec};
 
 use self::dns::{Dns, DnsQuery};
@@ -69,6 +69,8 @@ pub fn lookup_host(host: &str) -> Result<LookupHost> {
         let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
         let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
         let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?;
+        socket.set_read_timeout(Some(Duration::new(5, 0)))?;
+        socket.set_write_timeout(Some(Duration::new(5, 0)))?;
         socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?;
         socket.send(&packet_data)?;
 
index d5362c9f131f6b8149ec330f4cdcf69c920930fb..a3f202ccd97cbc492c2692c0692bb8e8448f7197 100644 (file)
@@ -8,10 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cmp;
 use io::{Error, ErrorKind, Result};
+use mem;
 use net::{SocketAddr, Shutdown};
 use path::Path;
 use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
 use vec::Vec;
@@ -77,15 +80,30 @@ pub fn only_v6(&self) -> Result<bool> {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn read_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::read_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"read_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn write_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::write_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"write_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
@@ -100,16 +118,36 @@ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
         Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_ttl not implemented"))
-    }
-
-    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_read_timeout not implemented"))
-    }
-
-    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_write_timeout not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
+    }
+
+    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"read_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
+    }
+
+    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"write_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 }
 
@@ -168,7 +206,10 @@ pub fn only_v6(&self) -> Result<bool> {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "TcpListener::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
@@ -179,8 +220,10 @@ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
         Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpListener::set_ttl not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
     }
 }
 
index 607c66c2ba70e3bf54023e631d921b8b471cf784..36f0819d308849cb8c087919fe0f4b8ee4fa46d4 100644 (file)
@@ -9,10 +9,13 @@
 // except according to those terms.
 
 use cell::UnsafeCell;
+use cmp;
 use io::{Error, ErrorKind, Result};
+use mem;
 use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
 use path::Path;
 use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
 
@@ -109,15 +112,30 @@ pub fn only_v6(&self) -> Result<bool> {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn read_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::read_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"read_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn write_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::write_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"write_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
@@ -144,16 +162,36 @@ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
         Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_ttl not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
     }
 
-    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_read_timeout not implemented"))
+    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"read_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 
-    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_write_timeout not implemented"))
+    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"write_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 
     pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
index ac3946672a3dd19a2db88346ed7d297281d4afb8..a6b0ada72b8fb7ef17172df0e645e3964d858d79 100644 (file)
@@ -84,3 +84,22 @@ pub struct TimeSpec {
     pub tv_sec: i64,
     pub tv_nsec: i32,
 }
+
+impl Deref for TimeSpec {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self as *const TimeSpec as *const u8,
+                                  mem::size_of::<TimeSpec>()) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for TimeSpec {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8,
+                                      mem::size_of::<TimeSpec>()) as &mut [u8]
+        }
+    }
+}
index d1c404195bc68d5bde33a61f08cb9765694c2394..910d802f05902a10b81d028aac8c1b994b06d1f6 100644 (file)
@@ -282,6 +282,7 @@ pub struct ipv6_mreq {
 pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
 
 pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
 pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
 pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
 pub const PIPE_WAIT: DWORD = 0x00000000;
index 1eb1730547642f18eb3fc162d192f977089c84b0..8073473f7ff5b8c6144d938adae1ae887a37d35a 100644 (file)
@@ -29,18 +29,43 @@ pub struct AnonPipe {
     inner: Handle,
 }
 
-pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+pub struct Pipes {
+    pub ours: AnonPipe,
+    pub theirs: AnonPipe,
+}
+
+/// Although this looks similar to `anon_pipe` in the Unix module it's actually
+/// subtly different. Here we'll return two pipes in the `Pipes` return value,
+/// but one is intended for "us" where as the other is intended for "someone
+/// else".
+///
+/// Currently the only use case for this function is pipes for stdio on
+/// processes in the standard library, so "ours" is the one that'll stay in our
+/// process whereas "theirs" will be inherited to a child.
+///
+/// The ours/theirs pipes are *not* specifically readable or writable. Each
+/// one only supports a read or a write, but which is which depends on the
+/// boolean flag given. If `ours_readable` is true then `ours` is readable where
+/// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is
+/// writable where `theirs` is readable.
+///
+/// Also note that the `ours` pipe is always a handle opened up in overlapped
+/// mode. This means that technically speaking it should only ever be used
+/// with `OVERLAPPED` instances, but also works out ok if it's only ever used
+/// once at a time (which we do indeed guarantee).
+pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
     // Note that we specifically do *not* use `CreatePipe` here because
     // unfortunately the anonymous pipes returned do not support overlapped
-    // operations.
-    //
-    // Instead, we create a "hopefully unique" name and create a named pipe
-    // which has overlapped operations enabled.
+    // operations. Instead, we create a "hopefully unique" name and create a
+    // named pipe which has overlapped operations enabled.
     //
-    // Once we do this, we connect do it as usual via `CreateFileW`, and then we
-    // return those reader/writer halves.
+    // Once we do this, we connect do it as usual via `CreateFileW`, and then
+    // we return those reader/writer halves. Note that the `ours` pipe return
+    // value is always the named pipe, whereas `theirs` is just the normal file.
+    // This should hopefully shield us from child processes which assume their
+    // stdout is a named pipe, which would indeed be odd!
     unsafe {
-        let reader;
+        let ours;
         let mut name;
         let mut tries = 0;
         let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS;
@@ -54,11 +79,16 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
                                   .encode_wide()
                                   .chain(Some(0))
                                   .collect::<Vec<_>>();
+            let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE |
+                c::FILE_FLAG_OVERLAPPED;
+            if ours_readable {
+                flags |= c::PIPE_ACCESS_INBOUND;
+            } else {
+                flags |= c::PIPE_ACCESS_OUTBOUND;
+            }
 
             let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
-                                             c::PIPE_ACCESS_INBOUND |
-                                             c::FILE_FLAG_FIRST_PIPE_INSTANCE |
-                                             c::FILE_FLAG_OVERLAPPED,
+                                             flags,
                                              c::PIPE_TYPE_BYTE |
                                              c::PIPE_READMODE_BYTE |
                                              c::PIPE_WAIT |
@@ -101,21 +131,28 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
                 }
                 return Err(err)
             }
-            reader = Handle::new(handle);
+            ours = Handle::new(handle);
             break
         }
 
-        // Connect to the named pipe we just created in write-only mode (also
-        // overlapped for async I/O below).
+        // Connect to the named pipe we just created. This handle is going to be
+        // returned in `theirs`, so if `ours` is readable we want this to be
+        // writable, otherwise if `ours` is writable we want this to be
+        // readable.
+        //
+        // Additionally we don't enable overlapped mode on this because most
+        // client processes aren't enabled to work with that.
         let mut opts = OpenOptions::new();
-        opts.write(true);
-        opts.read(false);
+        opts.write(ours_readable);
+        opts.read(!ours_readable);
         opts.share_mode(0);
-        opts.attributes(c::FILE_FLAG_OVERLAPPED);
-        let writer = File::open(Path::new(&name), &opts)?;
-        let writer = AnonPipe { inner: writer.into_handle() };
+        let theirs = File::open(Path::new(&name), &opts)?;
+        let theirs = AnonPipe { inner: theirs.into_handle() };
 
-        Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer.into_handle() }))
+        Ok(Pipes {
+            ours: AnonPipe { inner: ours },
+            theirs: AnonPipe { inner: theirs.into_handle() },
+        })
     }
 }
 
index 969de6b85a6aa93260e1194d8901baef16d057f6..7dc8959e1b6830f206d791b5aeabe224b29a8fce 100644 (file)
@@ -264,19 +264,15 @@ fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>)
             }
 
             Stdio::MakePipe => {
-                let (reader, writer) = pipe::anon_pipe()?;
-                let (ours, theirs) = if stdio_id == c::STD_INPUT_HANDLE {
-                    (writer, reader)
-                } else {
-                    (reader, writer)
-                };
-                *pipe = Some(ours);
+                let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
+                let pipes = pipe::anon_pipe(ours_readable)?;
+                *pipe = Some(pipes.ours);
                 cvt(unsafe {
-                    c::SetHandleInformation(theirs.handle().raw(),
+                    c::SetHandleInformation(pipes.theirs.handle().raw(),
                                             c::HANDLE_FLAG_INHERIT,
                                             c::HANDLE_FLAG_INHERIT)
                 })?;
-                Ok(theirs.into_handle())
+                Ok(pipes.theirs.into_handle())
             }
 
             Stdio::Handle(ref handle) => {
index 5d3084094fbddd4f02b375b724303fd8734ac157..597f05622a52e2e245895cf5671d07cdcaa98446 100644 (file)
@@ -207,7 +207,7 @@ unsafe fn unregister_dtor(key: Key) -> bool {
 // loop to basically match Unix semantics. If we don't reach a fixed point
 // after a short while then we just inevitably leak something most likely.
 //
-// # The article mentions crazy stuff about "/INCLUDE"?
+// # The article mentions weird stuff about "/INCLUDE"?
 //
 // It sure does! Specifically we're talking about this quote:
 //
index 81979fd41a6bf6f16ed820eb705973831b46328c..a2039db0e40c3ed4437912989f3a73b2f0df3c13 100644 (file)
@@ -648,6 +648,23 @@ pub fn park_timeout(dur: Duration) {
 /// A `ThreadId` is an opaque object that has a unique value for each thread
 /// that creates one. `ThreadId`s do not correspond to a thread's system-
 /// designated identifier.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(thread_id)]
+///
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+///     .spawn(|| {
+///         let thread = thread::current();
+///         let thread_id = thread.id();
+///     })
+///     .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
 #[unstable(feature = "thread_id", issue = "21507")]
 #[derive(Eq, PartialEq, Copy, Clone)]
 pub struct ThreadId(u64);
@@ -700,6 +717,22 @@ struct Inner {
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 /// A handle to a thread.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+///     .name("foo".into())
+///     .spawn(|| {
+///         let thread = thread::current();
+///         println!("thread name: {}", thread.name().unwrap());
+///     })
+///     .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
 pub struct Thread {
     inner: Arc<Inner>,
 }
@@ -723,6 +756,21 @@ fn new(name: Option<String>) -> Thread {
     /// Atomically makes the handle's token available if it is not already.
     ///
     /// See the module doc for more detail.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::thread;
+    ///
+    /// let handler = thread::Builder::new()
+    ///     .spawn(|| {
+    ///         let thread = thread::current();
+    ///         thread.unpark();
+    ///     })
+    ///     .unwrap();
+    ///
+    /// handler.join().unwrap();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unpark(&self) {
         let mut guard = self.inner.lock.lock().unwrap();
@@ -733,6 +781,23 @@ pub fn unpark(&self) {
     }
 
     /// Gets the thread's unique identifier.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(thread_id)]
+    ///
+    /// use std::thread;
+    ///
+    /// let handler = thread::Builder::new()
+    ///     .spawn(|| {
+    ///         let thread = thread::current();
+    ///         println!("thread id: {:?}", thread.id());
+    ///     })
+    ///     .unwrap();
+    ///
+    /// handler.join().unwrap();
+    /// ```
     #[unstable(feature = "thread_id", issue = "21507")]
     pub fn id(&self) -> ThreadId {
         self.inner.id
index 5d62175fbf23a7af4c44dbf9836ebb499102c086..d45dbd3f72342424592f5d4f21316a7444c6f19e 100644 (file)
@@ -926,7 +926,6 @@ fn enable_trace_macros = trace_macros,
         fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = custom_derive,
         fn enable_pushpop_unsafe = pushpop_unsafe,
-        fn enable_proc_macro = proc_macro,
     }
 }
 
index e7df454cf6a50220783c7c533d8934a8ff5250b3..5092412475872d624c38377791b5c7d4a5646b53 100644 (file)
@@ -279,9 +279,6 @@ pub fn new() -> Features {
     // instead of just the platforms on which it is the C ABI
     (active, abi_sysv64, "1.13.0", Some(36167)),
 
-    // Macros 1.1
-    (active, proc_macro, "1.13.0", Some(35900)),
-
     // Allows untagged unions `union U { ... }`
     (active, untagged_unions, "1.13.0", Some(32836)),
 
@@ -377,6 +374,8 @@ pub fn new() -> Features {
     // Allows `..` in tuple (struct) patterns
     (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
     (accepted, item_like_imports, "1.14.0", Some(35120)),
+    // Macros 1.1
+    (accepted, proc_macro, "1.15.0", Some(35900)),
 );
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -650,11 +649,7 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att
                                         is an experimental feature",
                                        cfg_fn!(fundamental))),
 
-    ("proc_macro_derive", Normal, Gated(Stability::Unstable,
-                                        "proc_macro",
-                                        "the `#[proc_macro_derive]` attribute \
-                                         is an experimental feature",
-                                        cfg_fn!(proc_macro))),
+    ("proc_macro_derive", Normal, Ungated),
 
     ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
                                                    "rustc_attrs",
@@ -760,7 +755,6 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
-    ("proc_macro", "proc_macro", cfg_fn!(proc_macro)),
 ];
 
 #[derive(Debug, Eq, PartialEq)]
index 9797e0003fc55865321d22a8ea6c453ee8d491f9..7bce00ebcab9529ab2a5589251e50980e2a39109 100644 (file)
@@ -542,19 +542,19 @@ pub fn noop_fold_arg<T: Folder>(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg {
 pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
     match *tt {
         TokenTree::Token(span, ref tok) =>
-            TokenTree::Token(span, fld.fold_token(tok.clone())),
+            TokenTree::Token(fld.new_span(span), fld.fold_token(tok.clone())),
         TokenTree::Delimited(span, ref delimed) => {
-            TokenTree::Delimited(span, Rc::new(
+            TokenTree::Delimited(fld.new_span(span), Rc::new(
                             Delimited {
                                 delim: delimed.delim,
-                                open_span: delimed.open_span,
+                                open_span: fld.new_span(delimed.open_span),
                                 tts: fld.fold_tts(&delimed.tts),
-                                close_span: delimed.close_span,
+                                close_span: fld.new_span(delimed.close_span),
                             }
                         ))
         },
         TokenTree::Sequence(span, ref seq) =>
-            TokenTree::Sequence(span,
+            TokenTree::Sequence(fld.new_span(span),
                        Rc::new(SequenceRepetition {
                            tts: fld.fold_tts(&seq.tts),
                            separator: seq.separator.clone().map(|tok| fld.fold_token(tok)),
@@ -647,7 +647,7 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
         inputs: inputs.move_map(|x| fld.fold_arg(x)),
         output: match output {
             FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(fld.fold_ty(ty)),
-            FunctionRetTy::Default(span) => FunctionRetTy::Default(span),
+            FunctionRetTy::Default(span) => FunctionRetTy::Default(fld.new_span(span)),
         },
         variadic: variadic
     })
@@ -674,7 +674,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
         ident: fld.fold_ident(ident),
         bounds: fld.fold_bounds(bounds),
         default: default.map(|x| fld.fold_ty(x)),
-        span: span
+        span: fld.new_span(span),
     }
 }
 
index 60e1882fcf582c4ad36f4f423ce3c2b29405641c..ff77732f5354ce3bc182ad68d0ea11d1f58be8ed 100644 (file)
@@ -125,16 +125,16 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
         let prelude_import_meta = attr::mk_list_word_item(Symbol::intern("prelude_import"));
         let list = attr::mk_list_item(Symbol::intern("feature"), vec![prelude_import_meta]);
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list);
-        try!(s.print_attribute(&fake_attr));
+        s.print_attribute(&fake_attr)?;
 
         // #![no_std]
         let no_std_meta = attr::mk_word_item(Symbol::intern("no_std"));
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), no_std_meta);
-        try!(s.print_attribute(&fake_attr));
+        s.print_attribute(&fake_attr)?;
     }
 
-    try!(s.print_mod(&krate.module, &krate.attrs));
-    try!(s.print_remaining_comments());
+    s.print_mod(&krate.module, &krate.attrs)?;
+    s.print_remaining_comments()?;
     eof(&mut s.s)
 }
 
@@ -387,10 +387,10 @@ pub fn fun_to_string(decl: &ast::FnDecl,
                      generics: &ast::Generics)
                      -> String {
     to_string(|s| {
-        try!(s.head(""));
-        try!(s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
-                   generics, &ast::Visibility::Inherited));
-        try!(s.end()); // Close the head box
+        s.head("")?;
+        s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
+                   generics, &ast::Visibility::Inherited)?;
+        s.end()?; // Close the head box
         s.end() // Close the outer box
     })
 }
@@ -398,9 +398,9 @@ pub fn fun_to_string(decl: &ast::FnDecl,
 pub fn block_to_string(blk: &ast::Block) -> String {
     to_string(|s| {
         // containing cbox, will be closed by print-block at }
-        try!(s.cbox(INDENT_UNIT));
+        s.cbox(INDENT_UNIT)?;
         // head-ibox, will be closed by print-block after {
-        try!(s.ibox(0));
+        s.ibox(0)?;
         s.print_block(blk)
     })
 }
@@ -461,7 +461,7 @@ pub trait PrintState<'a> {
     fn literals(&self) -> &Option<Vec<comments::Literal>>;
 
     fn word_space(&mut self, w: &str) -> io::Result<()> {
-        try!(word(self.writer(), w));
+        word(self.writer(), w)?;
         space(self.writer())
     }
 
@@ -490,7 +490,7 @@ fn is_bol(&mut self) -> bool {
 
     fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
         if !self.is_bol() {
-            try!(hardbreak(self.writer()))
+            hardbreak(self.writer())?
         }
         Ok(())
     }
@@ -514,11 +514,11 @@ fn end(&mut self) -> io::Result<()> {
     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()>
         where F: FnMut(&mut Self, &T) -> io::Result<()>,
     {
-        try!(self.rbox(0, b));
+        self.rbox(0, b)?;
         let mut first = true;
         for elt in elts {
-            if first { first = false; } else { try!(self.word_space(",")); }
-            try!(op(self, elt));
+            if first { first = false; } else { self.word_space(",")?; }
+            op(self, elt)?;
         }
         self.end()
     }
@@ -548,7 +548,7 @@ fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
     fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
         while let Some(ref cmnt) = self.next_comment() {
             if cmnt.pos < pos {
-                try!(self.print_comment(cmnt));
+                self.print_comment(cmnt)?;
                 self.cur_cmnt_and_lit().cur_cmnt += 1;
             } else {
                 break
@@ -562,36 +562,36 @@ fn print_comment(&mut self,
         match cmnt.style {
             comments::Mixed => {
                 assert_eq!(cmnt.lines.len(), 1);
-                try!(zerobreak(self.writer()));
-                try!(word(self.writer(), &cmnt.lines[0]));
+                zerobreak(self.writer())?;
+                word(self.writer(), &cmnt.lines[0])?;
                 zerobreak(self.writer())
             }
             comments::Isolated => {
-                try!(self.hardbreak_if_not_bol());
+                self.hardbreak_if_not_bol()?;
                 for line in &cmnt.lines {
                     // Don't print empty lines because they will end up as trailing
                     // whitespace
                     if !line.is_empty() {
-                        try!(word(self.writer(), &line[..]));
+                        word(self.writer(), &line[..])?;
                     }
-                    try!(hardbreak(self.writer()));
+                    hardbreak(self.writer())?;
                 }
                 Ok(())
             }
             comments::Trailing => {
                 if !self.is_bol() {
-                    try!(word(self.writer(), " "));
+                    word(self.writer(), " ")?;
                 }
                 if cmnt.lines.len() == 1 {
-                    try!(word(self.writer(), &cmnt.lines[0]));
+                    word(self.writer(), &cmnt.lines[0])?;
                     hardbreak(self.writer())
                 } else {
-                    try!(self.ibox(0));
+                    self.ibox(0)?;
                     for line in &cmnt.lines {
                         if !line.is_empty() {
-                            try!(word(self.writer(), &line[..]));
+                            word(self.writer(), &line[..])?;
                         }
-                        try!(hardbreak(self.writer()));
+                        hardbreak(self.writer())?;
                     }
                     self.end()
                 }
@@ -603,7 +603,7 @@ fn print_comment(&mut self,
                     _ => false
                 };
                 if is_semi || self.is_begin() || self.is_end() {
-                    try!(hardbreak(self.writer()));
+                    hardbreak(self.writer())?;
                 }
                 hardbreak(self.writer())
             }
@@ -625,7 +625,7 @@ fn next_comment(&mut self) -> Option<comments::Comment> {
     }
 
     fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
-        try!(self.maybe_print_comment(lit.span.lo));
+        self.maybe_print_comment(lit.span.lo)?;
         match self.next_lit(lit.span.lo) {
             Some(ref ltrl) => {
                 return word(self.writer(), &(*ltrl).lit);
@@ -730,15 +730,15 @@ fn print_either_attributes(&mut self,
         let mut count = 0;
         for attr in attrs {
             if attr.style == kind {
-                try!(self.print_attribute_inline(attr, is_inline));
+                self.print_attribute_inline(attr, is_inline)?;
                 if is_inline {
-                    try!(self.nbsp());
+                    self.nbsp()?;
                 }
                 count += 1;
             }
         }
         if count > 0 && trailing_hardbreak && !is_inline {
-            try!(self.hardbreak_if_not_bol());
+            self.hardbreak_if_not_bol()?;
         }
         Ok(())
     }
@@ -750,18 +750,18 @@ fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> {
     fn print_attribute_inline(&mut self, attr: &ast::Attribute,
                               is_inline: bool) -> io::Result<()> {
         if !is_inline {
-            try!(self.hardbreak_if_not_bol());
+            self.hardbreak_if_not_bol()?;
         }
-        try!(self.maybe_print_comment(attr.span.lo));
+        self.maybe_print_comment(attr.span.lo)?;
         if attr.is_sugared_doc {
-            try!(word(self.writer(), &attr.value_str().unwrap().as_str()));
+            word(self.writer(), &attr.value_str().unwrap().as_str())?;
             hardbreak(self.writer())
         } else {
             match attr.style {
-                ast::AttrStyle::Inner => try!(word(self.writer(), "#![")),
-                ast::AttrStyle::Outer => try!(word(self.writer(), "#[")),
+                ast::AttrStyle::Inner => word(self.writer(), "#![")?,
+                ast::AttrStyle::Outer => word(self.writer(), "#[")?,
             }
-            try!(self.print_meta_item(&attr.meta()));
+            self.print_meta_item(&attr.meta())?;
             word(self.writer(), "]")
         }
     }
@@ -778,30 +778,30 @@ fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()>
     }
 
     fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
-        try!(self.ibox(INDENT_UNIT));
+        self.ibox(INDENT_UNIT)?;
         match item.node {
             ast::MetaItemKind::Word => {
-                try!(word(self.writer(), &item.name.as_str()));
+                word(self.writer(), &item.name.as_str())?;
             }
             ast::MetaItemKind::NameValue(ref value) => {
-                try!(self.word_space(&item.name.as_str()));
-                try!(self.word_space("="));
-                try!(self.print_literal(value));
+                self.word_space(&item.name.as_str())?;
+                self.word_space("=")?;
+                self.print_literal(value)?;
             }
             ast::MetaItemKind::List(ref items) => {
-                try!(word(self.writer(), &item.name.as_str()));
-                try!(self.popen());
-                try!(self.commasep(Consistent,
+                word(self.writer(), &item.name.as_str())?;
+                self.popen()?;
+                self.commasep(Consistent,
                               &items[..],
-                              |s, i| s.print_meta_list_item(&i)));
-                try!(self.pclose());
+                              |s, i| s.print_meta_list_item(&i))?;
+                self.pclose()?;
             }
         }
         self.end()
     }
 
     fn space_if_not_bol(&mut self) -> io::Result<()> {
-        if !self.is_bol() { try!(space(self.writer())); }
+        if !self.is_bol() { space(self.writer())?; }
         Ok(())
     }
 
@@ -837,24 +837,24 @@ pub fn cbox(&mut self, u: usize) -> io::Result<()> {
     }
 
     pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
-        try!(word(&mut self.s, w));
+        word(&mut self.s, w)?;
         self.nbsp()
     }
 
     pub fn head(&mut self, w: &str) -> io::Result<()> {
         // outer-box is consistent
-        try!(self.cbox(INDENT_UNIT));
+        self.cbox(INDENT_UNIT)?;
         // head-box is inconsistent
-        try!(self.ibox(w.len() + 1));
+        self.ibox(w.len() + 1)?;
         // keyword that starts the head
         if !w.is_empty() {
-            try!(self.word_nbsp(w));
+            self.word_nbsp(w)?;
         }
         Ok(())
     }
 
     pub fn bopen(&mut self) -> io::Result<()> {
-        try!(word(&mut self.s, "{"));
+        word(&mut self.s, "{")?;
         self.end() // close the head-box
     }
 
@@ -864,11 +864,11 @@ pub fn bclose_(&mut self, span: syntax_pos::Span,
     }
     pub fn bclose_maybe_open(&mut self, span: syntax_pos::Span,
                              indented: usize, close_box: bool) -> io::Result<()> {
-        try!(self.maybe_print_comment(span.hi));
-        try!(self.break_offset_if_not_bol(1, -(indented as isize)));
-        try!(word(&mut self.s, "}"));
+        self.maybe_print_comment(span.hi)?;
+        self.break_offset_if_not_bol(1, -(indented as isize))?;
+        word(&mut self.s, "}")?;
         if close_box {
-            try!(self.end()); // close the outer-box
+            self.end()?; // close the outer-box
         }
         Ok(())
     }
@@ -901,10 +901,10 @@ pub fn break_offset_if_not_bol(&mut self, n: usize,
     // Synthesizes a comment that was not textually present in the original source
     // file.
     pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
-        try!(word(&mut self.s, "/*"));
-        try!(space(&mut self.s));
-        try!(word(&mut self.s, &text[..]));
-        try!(space(&mut self.s));
+        word(&mut self.s, "/*")?;
+        space(&mut self.s)?;
+        word(&mut self.s, &text[..])?;
+        space(&mut self.s)?;
         word(&mut self.s, "*/")
     }
 
@@ -918,18 +918,18 @@ pub fn commasep_cmnt<T, F, G>(&mut self,
         F: FnMut(&mut State, &T) -> io::Result<()>,
         G: FnMut(&T) -> syntax_pos::Span,
     {
-        try!(self.rbox(0, b));
+        self.rbox(0, b)?;
         let len = elts.len();
         let mut i = 0;
         for elt in elts {
-            try!(self.maybe_print_comment(get_span(elt).hi));
-            try!(op(self, elt));
+            self.maybe_print_comment(get_span(elt).hi)?;
+            op(self, elt)?;
             i += 1;
             if i < len {
-                try!(word(&mut self.s, ","));
-                try!(self.maybe_print_trailing_comment(get_span(elt),
-                                                  Some(get_span(&elts[i]).hi)));
-                try!(self.space_if_not_bol());
+                word(&mut self.s, ",")?;
+                self.maybe_print_trailing_comment(get_span(elt),
+                                                  Some(get_span(&elts[i]).hi))?;
+                self.space_if_not_bol()?;
             }
         }
         self.end()
@@ -942,18 +942,18 @@ pub fn commasep_exprs(&mut self, b: Breaks,
 
     pub fn print_mod(&mut self, _mod: &ast::Mod,
                      attrs: &[ast::Attribute]) -> io::Result<()> {
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
         for item in &_mod.items {
-            try!(self.print_item(&item));
+            self.print_item(&item)?;
         }
         Ok(())
     }
 
     pub fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod,
                              attrs: &[ast::Attribute]) -> io::Result<()> {
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
         for item in &nmod.items {
-            try!(self.print_foreign_item(item));
+            self.print_foreign_item(item)?;
         }
         Ok(())
     }
@@ -961,50 +961,50 @@ pub fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod,
     pub fn print_opt_lifetime(&mut self,
                               lifetime: &Option<ast::Lifetime>) -> io::Result<()> {
         if let Some(l) = *lifetime {
-            try!(self.print_lifetime(&l));
-            try!(self.nbsp());
+            self.print_lifetime(&l)?;
+            self.nbsp()?;
         }
         Ok(())
     }
 
     pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
-        try!(self.maybe_print_comment(ty.span.lo));
-        try!(self.ibox(0));
+        self.maybe_print_comment(ty.span.lo)?;
+        self.ibox(0)?;
         match ty.node {
             ast::TyKind::Slice(ref ty) => {
-                try!(word(&mut self.s, "["));
-                try!(self.print_type(&ty));
-                try!(word(&mut self.s, "]"));
+                word(&mut self.s, "[")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, "]")?;
             }
             ast::TyKind::Ptr(ref mt) => {
-                try!(word(&mut self.s, "*"));
+                word(&mut self.s, "*")?;
                 match mt.mutbl {
-                    ast::Mutability::Mutable => try!(self.word_nbsp("mut")),
-                    ast::Mutability::Immutable => try!(self.word_nbsp("const")),
+                    ast::Mutability::Mutable => self.word_nbsp("mut")?,
+                    ast::Mutability::Immutable => self.word_nbsp("const")?,
                 }
-                try!(self.print_type(&mt.ty));
+                self.print_type(&mt.ty)?;
             }
             ast::TyKind::Rptr(ref lifetime, ref mt) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.print_opt_lifetime(lifetime));
-                try!(self.print_mt(mt));
+                word(&mut self.s, "&")?;
+                self.print_opt_lifetime(lifetime)?;
+                self.print_mt(mt)?;
             }
             ast::TyKind::Never => {
-                try!(word(&mut self.s, "!"));
+                word(&mut self.s, "!")?;
             },
             ast::TyKind::Tup(ref elts) => {
-                try!(self.popen());
-                try!(self.commasep(Inconsistent, &elts[..],
-                              |s, ty| s.print_type(&ty)));
+                self.popen()?;
+                self.commasep(Inconsistent, &elts[..],
+                              |s, ty| s.print_type(&ty))?;
                 if elts.len() == 1 {
-                    try!(word(&mut self.s, ","));
+                    word(&mut self.s, ",")?;
                 }
-                try!(self.pclose());
+                self.pclose()?;
             }
             ast::TyKind::Paren(ref typ) => {
-                try!(self.popen());
-                try!(self.print_type(&typ));
-                try!(self.pclose());
+                self.popen()?;
+                self.print_type(&typ)?;
+                self.pclose()?;
             }
             ast::TyKind::BareFn(ref f) => {
                 let generics = ast::Generics {
@@ -1016,48 +1016,48 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
                     },
                     span: syntax_pos::DUMMY_SP,
                 };
-                try!(self.print_ty_fn(f.abi,
+                self.print_ty_fn(f.abi,
                                  f.unsafety,
                                  &f.decl,
                                  None,
-                                 &generics));
+                                 &generics)?;
             }
             ast::TyKind::Path(None, ref path) => {
-                try!(self.print_path(path, false, 0, false));
+                self.print_path(path, false, 0, false)?;
             }
             ast::TyKind::Path(Some(ref qself), ref path) => {
-                try!(self.print_qpath(path, qself, false))
+                self.print_qpath(path, qself, false)?
             }
             ast::TyKind::ObjectSum(ref ty, ref bounds) => {
-                try!(self.print_type(&ty));
-                try!(self.print_bounds("+", &bounds[..]));
+                self.print_type(&ty)?;
+                self.print_bounds("+", &bounds[..])?;
             }
             ast::TyKind::PolyTraitRef(ref bounds) => {
-                try!(self.print_bounds("", &bounds[..]));
+                self.print_bounds("", &bounds[..])?;
             }
             ast::TyKind::ImplTrait(ref bounds) => {
-                try!(self.print_bounds("impl ", &bounds[..]));
+                self.print_bounds("impl ", &bounds[..])?;
             }
             ast::TyKind::Array(ref ty, ref v) => {
-                try!(word(&mut self.s, "["));
-                try!(self.print_type(&ty));
-                try!(word(&mut self.s, "; "));
-                try!(self.print_expr(&v));
-                try!(word(&mut self.s, "]"));
+                word(&mut self.s, "[")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, "; ")?;
+                self.print_expr(&v)?;
+                word(&mut self.s, "]")?;
             }
             ast::TyKind::Typeof(ref e) => {
-                try!(word(&mut self.s, "typeof("));
-                try!(self.print_expr(&e));
-                try!(word(&mut self.s, ")"));
+                word(&mut self.s, "typeof(")?;
+                self.print_expr(&e)?;
+                word(&mut self.s, ")")?;
             }
             ast::TyKind::Infer => {
-                try!(word(&mut self.s, "_"));
+                word(&mut self.s, "_")?;
             }
             ast::TyKind::ImplicitSelf => {
-                try!(word(&mut self.s, "Self"));
+                word(&mut self.s, "Self")?;
             }
             ast::TyKind::Mac(ref m) => {
-                try!(self.print_mac(m, token::Paren));
+                self.print_mac(m, token::Paren)?;
             }
         }
         self.end()
@@ -1065,30 +1065,30 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
 
     pub fn print_foreign_item(&mut self,
                               item: &ast::ForeignItem) -> io::Result<()> {
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(item.span.lo));
-        try!(self.print_outer_attributes(&item.attrs));
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(item.span.lo)?;
+        self.print_outer_attributes(&item.attrs)?;
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
-                try!(self.head(""));
-                try!(self.print_fn(decl, ast::Unsafety::Normal,
+                self.head("")?;
+                self.print_fn(decl, ast::Unsafety::Normal,
                               ast::Constness::NotConst,
                               Abi::Rust, Some(item.ident),
-                              generics, &item.vis));
-                try!(self.end()); // end head-ibox
-                try!(word(&mut self.s, ";"));
+                              generics, &item.vis)?;
+                self.end()?; // end head-ibox
+                word(&mut self.s, ";")?;
                 self.end() // end the outer fn box
             }
             ast::ForeignItemKind::Static(ref t, m) => {
-                try!(self.head(&visibility_qualified(&item.vis, "static")));
+                self.head(&visibility_qualified(&item.vis, "static"))?;
                 if m {
-                    try!(self.word_space("mut"));
+                    self.word_space("mut")?;
                 }
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&t));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the head-ibox
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(&t)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
             }
         }
@@ -1101,15 +1101,15 @@ fn print_associated_const(&mut self,
                               vis: &ast::Visibility)
                               -> io::Result<()>
     {
-        try!(word(&mut self.s, &visibility_qualified(vis, "")));
-        try!(self.word_space("const"));
-        try!(self.print_ident(ident));
-        try!(self.word_space(":"));
-        try!(self.print_type(ty));
+        word(&mut self.s, &visibility_qualified(vis, ""))?;
+        self.word_space("const")?;
+        self.print_ident(ident)?;
+        self.word_space(":")?;
+        self.print_type(ty)?;
         if let Some(expr) = default {
-            try!(space(&mut self.s));
-            try!(self.word_space("="));
-            try!(self.print_expr(expr));
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.print_expr(expr)?;
         }
         word(&mut self.s, ";")
     }
@@ -1119,83 +1119,83 @@ fn print_associated_type(&mut self,
                              bounds: Option<&ast::TyParamBounds>,
                              ty: Option<&ast::Ty>)
                              -> io::Result<()> {
-        try!(self.word_space("type"));
-        try!(self.print_ident(ident));
+        self.word_space("type")?;
+        self.print_ident(ident)?;
         if let Some(bounds) = bounds {
-            try!(self.print_bounds(":", bounds));
+            self.print_bounds(":", bounds)?;
         }
         if let Some(ty) = ty {
-            try!(space(&mut self.s));
-            try!(self.word_space("="));
-            try!(self.print_type(ty));
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.print_type(ty)?;
         }
         word(&mut self.s, ";")
     }
 
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(item.span.lo));
-        try!(self.print_outer_attributes(&item.attrs));
-        try!(self.ann.pre(self, NodeItem(item)));
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(item.span.lo)?;
+        self.print_outer_attributes(&item.attrs)?;
+        self.ann.pre(self, NodeItem(item))?;
         match item.node {
             ast::ItemKind::ExternCrate(ref optional_path) => {
-                try!(self.head(&visibility_qualified(&item.vis, "extern crate")));
+                self.head(&visibility_qualified(&item.vis, "extern crate"))?;
                 if let Some(p) = *optional_path {
                     let val = p.as_str();
                     if val.contains("-") {
-                        try!(self.print_string(&val, ast::StrStyle::Cooked));
+                        self.print_string(&val, ast::StrStyle::Cooked)?;
                     } else {
-                        try!(self.print_name(p));
+                        self.print_name(p)?;
                     }
-                    try!(space(&mut self.s));
-                    try!(word(&mut self.s, "as"));
-                    try!(space(&mut self.s));
+                    space(&mut self.s)?;
+                    word(&mut self.s, "as")?;
+                    space(&mut self.s)?;
                 }
-                try!(self.print_ident(item.ident));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end inner head-block
-                try!(self.end()); // end outer head-block
+                self.print_ident(item.ident)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
             }
             ast::ItemKind::Use(ref vp) => {
-                try!(self.head(&visibility_qualified(&item.vis, "use")));
-                try!(self.print_view_path(&vp));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end inner head-block
-                try!(self.end()); // end outer head-block
+                self.head(&visibility_qualified(&item.vis, "use"))?;
+                self.print_view_path(&vp)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
             }
             ast::ItemKind::Static(ref ty, m, ref expr) => {
-                try!(self.head(&visibility_qualified(&item.vis, "static")));
+                self.head(&visibility_qualified(&item.vis, "static"))?;
                 if m == ast::Mutability::Mutable {
-                    try!(self.word_space("mut"));
+                    self.word_space("mut")?;
                 }
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&ty));
-                try!(space(&mut self.s));
-                try!(self.end()); // end the head-ibox
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
+                space(&mut self.s)?;
+                self.end()?; // end the head-ibox
 
-                try!(self.word_space("="));
-                try!(self.print_expr(&expr));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer cbox
+                self.word_space("=")?;
+                self.print_expr(&expr)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer cbox
             }
             ast::ItemKind::Const(ref ty, ref expr) => {
-                try!(self.head(&visibility_qualified(&item.vis, "const")));
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&ty));
-                try!(space(&mut self.s));
-                try!(self.end()); // end the head-ibox
-
-                try!(self.word_space("="));
-                try!(self.print_expr(&expr));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer cbox
+                self.head(&visibility_qualified(&item.vis, "const"))?;
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
+                space(&mut self.s)?;
+                self.end()?; // end the head-ibox
+
+                self.word_space("=")?;
+                self.print_expr(&expr)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer cbox
             }
             ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
-                try!(self.head(""));
-                try!(self.print_fn(
+                self.head("")?;
+                self.print_fn(
                     decl,
                     unsafety,
                     constness.node,
@@ -1203,68 +1203,68 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                     Some(item.ident),
                     typarams,
                     &item.vis
-                ));
-                try!(word(&mut self.s, " "));
-                try!(self.print_block_with_attrs(&body, &item.attrs));
+                )?;
+                word(&mut self.s, " ")?;
+                self.print_block_with_attrs(&body, &item.attrs)?;
             }
             ast::ItemKind::Mod(ref _mod) => {
-                try!(self.head(&visibility_qualified(&item.vis, "mod")));
-                try!(self.print_ident(item.ident));
-                try!(self.nbsp());
-                try!(self.bopen());
-                try!(self.print_mod(_mod, &item.attrs));
-                try!(self.bclose(item.span));
+                self.head(&visibility_qualified(&item.vis, "mod"))?;
+                self.print_ident(item.ident)?;
+                self.nbsp()?;
+                self.bopen()?;
+                self.print_mod(_mod, &item.attrs)?;
+                self.bclose(item.span)?;
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                try!(self.head("extern"));
-                try!(self.word_nbsp(&nmod.abi.to_string()));
-                try!(self.bopen());
-                try!(self.print_foreign_mod(nmod, &item.attrs));
-                try!(self.bclose(item.span));
+                self.head("extern")?;
+                self.word_nbsp(&nmod.abi.to_string())?;
+                self.bopen()?;
+                self.print_foreign_mod(nmod, &item.attrs)?;
+                self.bclose(item.span)?;
             }
             ast::ItemKind::Ty(ref ty, ref params) => {
-                try!(self.ibox(INDENT_UNIT));
-                try!(self.ibox(0));
-                try!(self.word_nbsp(&visibility_qualified(&item.vis, "type")));
-                try!(self.print_ident(item.ident));
-                try!(self.print_generics(params));
-                try!(self.end()); // end the inner ibox
-
-                try!(self.print_where_clause(&params.where_clause));
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_type(&ty));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer ibox
+                self.ibox(INDENT_UNIT)?;
+                self.ibox(0)?;
+                self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
+                self.print_ident(item.ident)?;
+                self.print_generics(params)?;
+                self.end()?; // end the inner ibox
+
+                self.print_where_clause(&params.where_clause)?;
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer ibox
             }
             ast::ItemKind::Enum(ref enum_definition, ref params) => {
-                try!(self.print_enum_def(
+                self.print_enum_def(
                     enum_definition,
                     params,
                     item.ident,
                     item.span,
                     &item.vis
-                ));
+                )?;
             }
             ast::ItemKind::Struct(ref struct_def, ref generics) => {
-                try!(self.head(&visibility_qualified(&item.vis, "struct")));
-                try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
+                self.head(&visibility_qualified(&item.vis, "struct"))?;
+                self.print_struct(&struct_def, generics, item.ident, item.span, true)?;
             }
             ast::ItemKind::Union(ref struct_def, ref generics) => {
-                try!(self.head(&visibility_qualified(&item.vis, "union")));
-                try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
+                self.head(&visibility_qualified(&item.vis, "union"))?;
+                self.print_struct(&struct_def, generics, item.ident, item.span, true)?;
             }
             ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
-                try!(self.head(""));
-                try!(self.print_visibility(&item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("impl"));
-                try!(self.print_trait_ref(trait_ref));
-                try!(space(&mut self.s));
-                try!(self.word_space("for"));
-                try!(self.word_space(".."));
-                try!(self.bopen());
-                try!(self.bclose(item.span));
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("impl")?;
+                self.print_trait_ref(trait_ref)?;
+                space(&mut self.s)?;
+                self.word_space("for")?;
+                self.word_space("..")?;
+                self.bopen()?;
+                self.bclose(item.span)?;
             }
             ast::ItemKind::Impl(unsafety,
                           polarity,
@@ -1272,77 +1272,77 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                           ref opt_trait,
                           ref ty,
                           ref impl_items) => {
-                try!(self.head(""));
-                try!(self.print_visibility(&item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("impl"));
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("impl")?;
 
                 if generics.is_parameterized() {
-                    try!(self.print_generics(generics));
-                    try!(space(&mut self.s));
+                    self.print_generics(generics)?;
+                    space(&mut self.s)?;
                 }
 
                 match polarity {
                     ast::ImplPolarity::Negative => {
-                        try!(word(&mut self.s, "!"));
+                        word(&mut self.s, "!")?;
                     },
                     _ => {}
                 }
 
                 if let Some(ref t) = *opt_trait {
-                    try!(self.print_trait_ref(t));
-                    try!(space(&mut self.s));
-                    try!(self.word_space("for"));
+                    self.print_trait_ref(t)?;
+                    space(&mut self.s)?;
+                    self.word_space("for")?;
                 }
 
-                try!(self.print_type(&ty));
-                try!(self.print_where_clause(&generics.where_clause));
+                self.print_type(&ty)?;
+                self.print_where_clause(&generics.where_clause)?;
 
-                try!(space(&mut self.s));
-                try!(self.bopen());
-                try!(self.print_inner_attributes(&item.attrs));
+                space(&mut self.s)?;
+                self.bopen()?;
+                self.print_inner_attributes(&item.attrs)?;
                 for impl_item in impl_items {
-                    try!(self.print_impl_item(impl_item));
+                    self.print_impl_item(impl_item)?;
                 }
-                try!(self.bclose(item.span));
+                self.bclose(item.span)?;
             }
             ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => {
-                try!(self.head(""));
-                try!(self.print_visibility(&item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("trait"));
-                try!(self.print_ident(item.ident));
-                try!(self.print_generics(generics));
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("trait")?;
+                self.print_ident(item.ident)?;
+                self.print_generics(generics)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
                     if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        try!(space(&mut self.s));
-                        try!(self.word_space("for ?"));
-                        try!(self.print_trait_ref(&ptr.trait_ref));
+                        space(&mut self.s)?;
+                        self.word_space("for ?")?;
+                        self.print_trait_ref(&ptr.trait_ref)?;
                     } else {
                         real_bounds.push(b.clone());
                     }
                 }
-                try!(self.print_bounds(":", &real_bounds[..]));
-                try!(self.print_where_clause(&generics.where_clause));
-                try!(word(&mut self.s, " "));
-                try!(self.bopen());
+                self.print_bounds(":", &real_bounds[..])?;
+                self.print_where_clause(&generics.where_clause)?;
+                word(&mut self.s, " ")?;
+                self.bopen()?;
                 for trait_item in trait_items {
-                    try!(self.print_trait_item(trait_item));
+                    self.print_trait_item(trait_item)?;
                 }
-                try!(self.bclose(item.span));
+                self.bclose(item.span)?;
             }
             ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
-                try!(self.print_visibility(&item.vis));
-                try!(self.print_path(&node.path, false, 0, false));
-                try!(word(&mut self.s, "! "));
-                try!(self.print_ident(item.ident));
-                try!(self.cbox(INDENT_UNIT));
-                try!(self.popen());
-                try!(self.print_tts(&node.tts[..]));
-                try!(self.pclose());
-                try!(word(&mut self.s, ";"));
-                try!(self.end());
+                self.print_visibility(&item.vis)?;
+                self.print_path(&node.path, false, 0, false)?;
+                word(&mut self.s, "! ")?;
+                self.print_ident(item.ident)?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(&node.tts[..])?;
+                self.pclose()?;
+                word(&mut self.s, ";")?;
+                self.end()?;
             }
         }
         self.ann.post(self, NodeItem(item))
@@ -1354,23 +1354,23 @@ fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> {
 
     fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> {
         if !lifetimes.is_empty() {
-            try!(word(&mut self.s, "for<"));
+            word(&mut self.s, "for<")?;
             let mut comma = false;
             for lifetime_def in lifetimes {
                 if comma {
-                    try!(self.word_space(","))
+                    self.word_space(",")?
                 }
-                try!(self.print_outer_attributes_inline(&lifetime_def.attrs));
-                try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds));
+                self.print_outer_attributes_inline(&lifetime_def.attrs)?;
+                self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)?;
                 comma = true;
             }
-            try!(word(&mut self.s, ">"));
+            word(&mut self.s, ">")?;
         }
         Ok(())
     }
 
     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> io::Result<()> {
-        try!(self.print_formal_lifetime_list(&t.bound_lifetimes));
+        self.print_formal_lifetime_list(&t.bound_lifetimes)?;
         self.print_trait_ref(&t.trait_ref)
     }
 
@@ -1378,27 +1378,27 @@ pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
                           generics: &ast::Generics, ident: ast::Ident,
                           span: syntax_pos::Span,
                           visibility: &ast::Visibility) -> io::Result<()> {
-        try!(self.head(&visibility_qualified(visibility, "enum")));
-        try!(self.print_ident(ident));
-        try!(self.print_generics(generics));
-        try!(self.print_where_clause(&generics.where_clause));
-        try!(space(&mut self.s));
+        self.head(&visibility_qualified(visibility, "enum"))?;
+        self.print_ident(ident)?;
+        self.print_generics(generics)?;
+        self.print_where_clause(&generics.where_clause)?;
+        space(&mut self.s)?;
         self.print_variants(&enum_definition.variants, span)
     }
 
     pub fn print_variants(&mut self,
                           variants: &[ast::Variant],
                           span: syntax_pos::Span) -> io::Result<()> {
-        try!(self.bopen());
+        self.bopen()?;
         for v in variants {
-            try!(self.space_if_not_bol());
-            try!(self.maybe_print_comment(v.span.lo));
-            try!(self.print_outer_attributes(&v.node.attrs));
-            try!(self.ibox(INDENT_UNIT));
-            try!(self.print_variant(v));
-            try!(word(&mut self.s, ","));
-            try!(self.end());
-            try!(self.maybe_print_trailing_comment(v.span, None));
+            self.space_if_not_bol()?;
+            self.maybe_print_comment(v.span.lo)?;
+            self.print_outer_attributes(&v.node.attrs)?;
+            self.ibox(INDENT_UNIT)?;
+            self.print_variant(v)?;
+            word(&mut self.s, ",")?;
+            self.end()?;
+            self.maybe_print_trailing_comment(v.span, None)?;
         }
         self.bclose(span)
     }
@@ -1421,43 +1421,43 @@ pub fn print_struct(&mut self,
                         ident: ast::Ident,
                         span: syntax_pos::Span,
                         print_finalizer: bool) -> io::Result<()> {
-        try!(self.print_ident(ident));
-        try!(self.print_generics(generics));
+        self.print_ident(ident)?;
+        self.print_generics(generics)?;
         if !struct_def.is_struct() {
             if struct_def.is_tuple() {
-                try!(self.popen());
-                try!(self.commasep(
+                self.popen()?;
+                self.commasep(
                     Inconsistent, struct_def.fields(),
                     |s, field| {
-                        try!(s.maybe_print_comment(field.span.lo));
-                        try!(s.print_outer_attributes(&field.attrs));
-                        try!(s.print_visibility(&field.vis));
+                        s.maybe_print_comment(field.span.lo)?;
+                        s.print_outer_attributes(&field.attrs)?;
+                        s.print_visibility(&field.vis)?;
                         s.print_type(&field.ty)
                     }
-                ));
-                try!(self.pclose());
+                )?;
+                self.pclose()?;
             }
-            try!(self.print_where_clause(&generics.where_clause));
+            self.print_where_clause(&generics.where_clause)?;
             if print_finalizer {
-                try!(word(&mut self.s, ";"));
+                word(&mut self.s, ";")?;
             }
-            try!(self.end());
+            self.end()?;
             self.end() // close the outer-box
         } else {
-            try!(self.print_where_clause(&generics.where_clause));
-            try!(self.nbsp());
-            try!(self.bopen());
-            try!(self.hardbreak_if_not_bol());
+            self.print_where_clause(&generics.where_clause)?;
+            self.nbsp()?;
+            self.bopen()?;
+            self.hardbreak_if_not_bol()?;
 
             for field in struct_def.fields() {
-                try!(self.hardbreak_if_not_bol());
-                try!(self.maybe_print_comment(field.span.lo));
-                try!(self.print_outer_attributes(&field.attrs));
-                try!(self.print_visibility(&field.vis));
-                try!(self.print_ident(field.ident.unwrap()));
-                try!(self.word_nbsp(":"));
-                try!(self.print_type(&field.ty));
-                try!(word(&mut self.s, ","));
+                self.hardbreak_if_not_bol()?;
+                self.maybe_print_comment(field.span.lo)?;
+                self.print_outer_attributes(&field.attrs)?;
+                self.print_visibility(&field.vis)?;
+                self.print_ident(field.ident.unwrap())?;
+                self.word_nbsp(":")?;
+                self.print_type(&field.ty)?;
+                word(&mut self.s, ",")?;
             }
 
             self.bclose(span)
@@ -1474,7 +1474,7 @@ pub fn print_struct(&mut self,
     pub fn print_tt(&mut self, tt: &tokenstream::TokenTree) -> io::Result<()> {
         match *tt {
             TokenTree::Token(_, ref tk) => {
-                try!(word(&mut self.s, &token_to_string(tk)));
+                word(&mut self.s, &token_to_string(tk))?;
                 match *tk {
                     parse::token::DocComment(..) => {
                         hardbreak(&mut self.s)
@@ -1483,20 +1483,20 @@ pub fn print_tt(&mut self, tt: &tokenstream::TokenTree) -> io::Result<()> {
                 }
             }
             TokenTree::Delimited(_, ref delimed) => {
-                try!(word(&mut self.s, &token_to_string(&delimed.open_token())));
-                try!(space(&mut self.s));
-                try!(self.print_tts(&delimed.tts));
-                try!(space(&mut self.s));
+                word(&mut self.s, &token_to_string(&delimed.open_token()))?;
+                space(&mut self.s)?;
+                self.print_tts(&delimed.tts)?;
+                space(&mut self.s)?;
                 word(&mut self.s, &token_to_string(&delimed.close_token()))
             },
             TokenTree::Sequence(_, ref seq) => {
-                try!(word(&mut self.s, "$("));
+                word(&mut self.s, "$(")?;
                 for tt_elt in &seq.tts {
-                    try!(self.print_tt(tt_elt));
+                    self.print_tt(tt_elt)?;
                 }
-                try!(word(&mut self.s, ")"));
+                word(&mut self.s, ")")?;
                 if let Some(ref tk) = seq.separator {
-                    try!(word(&mut self.s, &token_to_string(tk)));
+                    word(&mut self.s, &token_to_string(tk))?;
                 }
                 match seq.op {
                     tokenstream::KleeneOp::ZeroOrMore => word(&mut self.s, "*"),
@@ -1507,24 +1507,24 @@ pub fn print_tt(&mut self, tt: &tokenstream::TokenTree) -> io::Result<()> {
     }
 
     pub fn print_tts(&mut self, tts: &[tokenstream::TokenTree]) -> io::Result<()> {
-        try!(self.ibox(0));
+        self.ibox(0)?;
         for (i, tt) in tts.iter().enumerate() {
             if i != 0 {
-                try!(space(&mut self.s));
+                space(&mut self.s)?;
             }
-            try!(self.print_tt(tt));
+            self.print_tt(tt)?;
         }
         self.end()
     }
 
     pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
-        try!(self.head(""));
+        self.head("")?;
         let generics = ast::Generics::default();
-        try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
+        self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
         match v.node.disr_expr {
             Some(ref d) => {
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
+                space(&mut self.s)?;
+                self.word_space("=")?;
                 self.print_expr(&d)
             }
             _ => Ok(())
@@ -1547,31 +1547,31 @@ pub fn print_method_sig(&mut self,
 
     pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
                             -> io::Result<()> {
-        try!(self.ann.pre(self, NodeSubItem(ti.id)));
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(ti.span.lo));
-        try!(self.print_outer_attributes(&ti.attrs));
+        self.ann.pre(self, NodeSubItem(ti.id))?;
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(ti.span.lo)?;
+        self.print_outer_attributes(&ti.attrs)?;
         match ti.node {
             ast::TraitItemKind::Const(ref ty, ref default) => {
-                try!(self.print_associated_const(ti.ident, &ty,
+                self.print_associated_const(ti.ident, &ty,
                                             default.as_ref().map(|expr| &**expr),
-                                            &ast::Visibility::Inherited));
+                                            &ast::Visibility::Inherited)?;
             }
             ast::TraitItemKind::Method(ref sig, ref body) => {
                 if body.is_some() {
-                    try!(self.head(""));
+                    self.head("")?;
                 }
-                try!(self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited));
+                self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited)?;
                 if let Some(ref body) = *body {
-                    try!(self.nbsp());
-                    try!(self.print_block_with_attrs(body, &ti.attrs));
+                    self.nbsp()?;
+                    self.print_block_with_attrs(body, &ti.attrs)?;
                 } else {
-                    try!(word(&mut self.s, ";"));
+                    word(&mut self.s, ";")?;
                 }
             }
             ast::TraitItemKind::Type(ref bounds, ref default) => {
-                try!(self.print_associated_type(ti.ident, Some(bounds),
-                                           default.as_ref().map(|ty| &**ty)));
+                self.print_associated_type(ti.ident, Some(bounds),
+                                           default.as_ref().map(|ty| &**ty))?;
             }
             ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
                 // code copied from ItemKind::Mac:
@@ -1589,85 +1589,85 @@ pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
     }
 
     pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
-        try!(self.ann.pre(self, NodeSubItem(ii.id)));
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(ii.span.lo));
-        try!(self.print_outer_attributes(&ii.attrs));
+        self.ann.pre(self, NodeSubItem(ii.id))?;
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(ii.span.lo)?;
+        self.print_outer_attributes(&ii.attrs)?;
         if let ast::Defaultness::Default = ii.defaultness {
-            try!(self.word_nbsp("default"));
+            self.word_nbsp("default")?;
         }
         match ii.node {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
-                try!(self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis));
+                self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?;
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
-                try!(self.head(""));
-                try!(self.print_method_sig(ii.ident, sig, &ii.vis));
-                try!(self.nbsp());
-                try!(self.print_block_with_attrs(body, &ii.attrs));
+                self.head("")?;
+                self.print_method_sig(ii.ident, sig, &ii.vis)?;
+                self.nbsp()?;
+                self.print_block_with_attrs(body, &ii.attrs)?;
             }
             ast::ImplItemKind::Type(ref ty) => {
-                try!(self.print_associated_type(ii.ident, None, Some(ty)));
+                self.print_associated_type(ii.ident, None, Some(ty))?;
             }
             ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
                 // code copied from ItemKind::Mac:
-                try!(self.print_path(&node.path, false, 0, false));
-                try!(word(&mut self.s, "! "));
-                try!(self.cbox(INDENT_UNIT));
-                try!(self.popen());
-                try!(self.print_tts(&node.tts[..]));
-                try!(self.pclose());
-                try!(word(&mut self.s, ";"));
-                try!(self.end())
+                self.print_path(&node.path, false, 0, false)?;
+                word(&mut self.s, "! ")?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(&node.tts[..])?;
+                self.pclose()?;
+                word(&mut self.s, ";")?;
+                self.end()?
             }
         }
         self.ann.post(self, NodeSubItem(ii.id))
     }
 
     pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
-        try!(self.maybe_print_comment(st.span.lo));
+        self.maybe_print_comment(st.span.lo)?;
         match st.node {
             ast::StmtKind::Local(ref loc) => {
-                try!(self.print_outer_attributes(&loc.attrs));
-                try!(self.space_if_not_bol());
-                try!(self.ibox(INDENT_UNIT));
-                try!(self.word_nbsp("let"));
-
-                try!(self.ibox(INDENT_UNIT));
-                try!(self.print_local_decl(&loc));
-                try!(self.end());
+                self.print_outer_attributes(&loc.attrs)?;
+                self.space_if_not_bol()?;
+                self.ibox(INDENT_UNIT)?;
+                self.word_nbsp("let")?;
+
+                self.ibox(INDENT_UNIT)?;
+                self.print_local_decl(&loc)?;
+                self.end()?;
                 if let Some(ref init) = loc.init {
-                    try!(self.nbsp());
-                    try!(self.word_space("="));
-                    try!(self.print_expr(&init));
+                    self.nbsp()?;
+                    self.word_space("=")?;
+                    self.print_expr(&init)?;
                 }
-                try!(word(&mut self.s, ";"));
+                word(&mut self.s, ";")?;
                 self.end()?;
             }
             ast::StmtKind::Item(ref item) => self.print_item(&item)?,
             ast::StmtKind::Expr(ref expr) => {
-                try!(self.space_if_not_bol());
-                try!(self.print_expr_outer_attr_style(&expr, false));
+                self.space_if_not_bol()?;
+                self.print_expr_outer_attr_style(&expr, false)?;
                 if parse::classify::expr_requires_semi_to_be_stmt(expr) {
-                    try!(word(&mut self.s, ";"));
+                    word(&mut self.s, ";")?;
                 }
             }
             ast::StmtKind::Semi(ref expr) => {
-                try!(self.space_if_not_bol());
-                try!(self.print_expr_outer_attr_style(&expr, false));
-                try!(word(&mut self.s, ";"));
+                self.space_if_not_bol()?;
+                self.print_expr_outer_attr_style(&expr, false)?;
+                word(&mut self.s, ";")?;
             }
             ast::StmtKind::Mac(ref mac) => {
                 let (ref mac, style, ref attrs) = **mac;
-                try!(self.space_if_not_bol());
-                try!(self.print_outer_attributes(&attrs));
+                self.space_if_not_bol()?;
+                self.print_outer_attributes(&attrs)?;
                 let delim = match style {
                     ast::MacStmtStyle::Braces => token::Brace,
                     _ => token::Paren
                 };
-                try!(self.print_mac(&mac, delim));
+                self.print_mac(&mac, delim)?;
                 if style == ast::MacStmtStyle::Semicolon {
-                    try!(word(&mut self.s, ";"));
+                    word(&mut self.s, ";")?;
                 }
             }
         }
@@ -1705,28 +1705,28 @@ pub fn print_block_maybe_unclosed(&mut self,
                                       attrs: &[ast::Attribute],
                                       close_box: bool) -> io::Result<()> {
         match blk.rules {
-            BlockCheckMode::Unsafe(..) => try!(self.word_space("unsafe")),
+            BlockCheckMode::Unsafe(..) => self.word_space("unsafe")?,
             BlockCheckMode::Default => ()
         }
-        try!(self.maybe_print_comment(blk.span.lo));
-        try!(self.ann.pre(self, NodeBlock(blk)));
-        try!(self.bopen());
+        self.maybe_print_comment(blk.span.lo)?;
+        self.ann.pre(self, NodeBlock(blk))?;
+        self.bopen()?;
 
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
 
         for (i, st) in blk.stmts.iter().enumerate() {
             match st.node {
                 ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
-                    try!(self.maybe_print_comment(st.span.lo));
-                    try!(self.space_if_not_bol());
-                    try!(self.print_expr_outer_attr_style(&expr, false));
-                    try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
+                    self.maybe_print_comment(st.span.lo)?;
+                    self.space_if_not_bol()?;
+                    self.print_expr_outer_attr_style(&expr, false)?;
+                    self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
                 }
-                _ => try!(self.print_stmt(st)),
+                _ => self.print_stmt(st)?,
             }
         }
 
-        try!(self.bclose_maybe_open(blk.span, indented, close_box));
+        self.bclose_maybe_open(blk.span, indented, close_box)?;
         self.ann.post(self, NodeBlock(blk))
     }
 
@@ -1736,32 +1736,32 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
                 match _else.node {
                     // "another else-if"
                     ast::ExprKind::If(ref i, ref then, ref e) => {
-                        try!(self.cbox(INDENT_UNIT - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else if "));
-                        try!(self.print_expr(&i));
-                        try!(space(&mut self.s));
-                        try!(self.print_block(&then));
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        word(&mut self.s, " else if ")?;
+                        self.print_expr(&i)?;
+                        space(&mut self.s)?;
+                        self.print_block(&then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
                     ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
-                        try!(self.cbox(INDENT_UNIT - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else if let "));
-                        try!(self.print_pat(&pat));
-                        try!(space(&mut self.s));
-                        try!(self.word_space("="));
-                        try!(self.print_expr(&expr));
-                        try!(space(&mut self.s));
-                        try!(self.print_block(&then));
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        word(&mut self.s, " else if let ")?;
+                        self.print_pat(&pat)?;
+                        space(&mut self.s)?;
+                        self.word_space("=")?;
+                        self.print_expr(&expr)?;
+                        space(&mut self.s)?;
+                        self.print_block(&then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "final else"
                     ast::ExprKind::Block(ref b) => {
-                        try!(self.cbox(INDENT_UNIT - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else "));
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        word(&mut self.s, " else ")?;
                         self.print_block(&b)
                     }
                     // BLEAH, constraints would be great here
@@ -1776,39 +1776,39 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
 
     pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
                     elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        try!(self.head("if"));
-        try!(self.print_expr(test));
-        try!(space(&mut self.s));
-        try!(self.print_block(blk));
+        self.head("if")?;
+        self.print_expr(test)?;
+        space(&mut self.s)?;
+        self.print_block(blk)?;
         self.print_else(elseopt)
     }
 
     pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
                         elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        try!(self.head("if let"));
-        try!(self.print_pat(pat));
-        try!(space(&mut self.s));
-        try!(self.word_space("="));
-        try!(self.print_expr(expr));
-        try!(space(&mut self.s));
-        try!(self.print_block(blk));
+        self.head("if let")?;
+        self.print_pat(pat)?;
+        space(&mut self.s)?;
+        self.word_space("=")?;
+        self.print_expr(expr)?;
+        space(&mut self.s)?;
+        self.print_block(blk)?;
         self.print_else(elseopt)
     }
 
     pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
                      -> io::Result<()> {
-        try!(self.print_path(&m.node.path, false, 0, false));
-        try!(word(&mut self.s, "!"));
+        self.print_path(&m.node.path, false, 0, false)?;
+        word(&mut self.s, "!")?;
         match delim {
-            token::Paren => try!(self.popen()),
-            token::Bracket => try!(word(&mut self.s, "[")),
+            token::Paren => self.popen()?,
+            token::Bracket => word(&mut self.s, "[")?,
             token::Brace => {
-                try!(self.head(""));
-                try!(self.bopen());
+                self.head("")?;
+                self.bopen()?;
             }
             token::NoDelim => {}
         }
-        try!(self.print_tts(&m.node.tts));
+        self.print_tts(&m.node.tts)?;
         match delim {
             token::Paren => self.pclose(),
             token::Bracket => word(&mut self.s, "]"),
@@ -1819,8 +1819,8 @@ pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
 
 
     fn print_call_post(&mut self, args: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.popen());
-        try!(self.commasep_exprs(Inconsistent, args));
+        self.popen()?;
+        self.commasep_exprs(Inconsistent, args)?;
         self.pclose()
     }
 
@@ -1842,11 +1842,11 @@ pub fn check_expr_bin_needs_paren(&mut self, sub_expr: &ast::Expr,
     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> io::Result<()> {
         let needs_par = needs_parentheses(expr);
         if needs_par {
-            try!(self.popen());
+            self.popen()?;
         }
-        try!(self.print_expr(expr));
+        self.print_expr(expr)?;
         if needs_par {
-            try!(self.pclose());
+            self.pclose()?;
         }
         Ok(())
     }
@@ -1854,19 +1854,19 @@ pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> io::Result<()> {
     fn print_expr_in_place(&mut self,
                            place: &ast::Expr,
                            expr: &ast::Expr) -> io::Result<()> {
-        try!(self.print_expr_maybe_paren(place));
-        try!(space(&mut self.s));
-        try!(self.word_space("<-"));
+        self.print_expr_maybe_paren(place)?;
+        space(&mut self.s)?;
+        self.word_space("<-")?;
         self.print_expr_maybe_paren(expr)
     }
 
     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>],
                       attrs: &[Attribute]) -> io::Result<()> {
-        try!(self.ibox(INDENT_UNIT));
-        try!(word(&mut self.s, "["));
-        try!(self.print_inner_attributes_inline(attrs));
-        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
-        try!(word(&mut self.s, "]"));
+        self.ibox(INDENT_UNIT)?;
+        word(&mut self.s, "[")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        word(&mut self.s, "]")?;
         self.end()
     }
 
@@ -1874,13 +1874,13 @@ fn print_expr_repeat(&mut self,
                          element: &ast::Expr,
                          count: &ast::Expr,
                          attrs: &[Attribute]) -> io::Result<()> {
-        try!(self.ibox(INDENT_UNIT));
-        try!(word(&mut self.s, "["));
-        try!(self.print_inner_attributes_inline(attrs));
-        try!(self.print_expr(element));
-        try!(self.word_space(";"));
-        try!(self.print_expr(count));
-        try!(word(&mut self.s, "]"));
+        self.ibox(INDENT_UNIT)?;
+        word(&mut self.s, "[")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.print_expr(element)?;
+        self.word_space(";")?;
+        self.print_expr(count)?;
+        word(&mut self.s, "]")?;
         self.end()
     }
 
@@ -1889,48 +1889,48 @@ fn print_expr_struct(&mut self,
                          fields: &[ast::Field],
                          wth: &Option<P<ast::Expr>>,
                          attrs: &[Attribute]) -> io::Result<()> {
-        try!(self.print_path(path, true, 0, false));
-        try!(word(&mut self.s, "{"));
-        try!(self.print_inner_attributes_inline(attrs));
-        try!(self.commasep_cmnt(
+        self.print_path(path, true, 0, false)?;
+        word(&mut self.s, "{")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_cmnt(
             Consistent,
             &fields[..],
             |s, field| {
-                try!(s.ibox(INDENT_UNIT));
+                s.ibox(INDENT_UNIT)?;
                 if !field.is_shorthand {
-                    try!(s.print_ident(field.ident.node));
-                    try!(s.word_space(":"));
+                    s.print_ident(field.ident.node)?;
+                    s.word_space(":")?;
                 }
-                try!(s.print_expr(&field.expr));
+                s.print_expr(&field.expr)?;
                 s.end()
             },
-            |f| f.span));
+            |f| f.span)?;
         match *wth {
             Some(ref expr) => {
-                try!(self.ibox(INDENT_UNIT));
+                self.ibox(INDENT_UNIT)?;
                 if !fields.is_empty() {
-                    try!(word(&mut self.s, ","));
-                    try!(space(&mut self.s));
+                    word(&mut self.s, ",")?;
+                    space(&mut self.s)?;
                 }
-                try!(word(&mut self.s, ".."));
-                try!(self.print_expr(&expr));
-                try!(self.end());
+                word(&mut self.s, "..")?;
+                self.print_expr(&expr)?;
+                self.end()?;
             }
             _ => if !fields.is_empty() {
-                try!(word(&mut self.s, ","))
+                word(&mut self.s, ",")?
             }
         }
-        try!(word(&mut self.s, "}"));
+        word(&mut self.s, "}")?;
         Ok(())
     }
 
     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>],
                       attrs: &[Attribute]) -> io::Result<()> {
-        try!(self.popen());
-        try!(self.print_inner_attributes_inline(attrs));
-        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
+        self.popen()?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
         if exprs.len() == 1 {
-            try!(word(&mut self.s, ","));
+            word(&mut self.s, ",")?;
         }
         self.pclose()
     }
@@ -1938,7 +1938,7 @@ fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>],
     fn print_expr_call(&mut self,
                        func: &ast::Expr,
                        args: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.print_expr_maybe_paren(func));
+        self.print_expr_maybe_paren(func)?;
         self.print_call_post(args)
     }
 
@@ -1947,14 +1947,14 @@ fn print_expr_method_call(&mut self,
                               tys: &[P<ast::Ty>],
                               args: &[P<ast::Expr>]) -> io::Result<()> {
         let base_args = &args[1..];
-        try!(self.print_expr(&args[0]));
-        try!(word(&mut self.s, "."));
-        try!(self.print_ident(ident.node));
+        self.print_expr(&args[0])?;
+        word(&mut self.s, ".")?;
+        self.print_ident(ident.node)?;
         if !tys.is_empty() {
-            try!(word(&mut self.s, "::<"));
-            try!(self.commasep(Inconsistent, tys,
-                          |s, ty| s.print_type(&ty)));
-            try!(word(&mut self.s, ">"));
+            word(&mut self.s, "::<")?;
+            self.commasep(Inconsistent, tys,
+                          |s, ty| s.print_type(&ty))?;
+            word(&mut self.s, ">")?;
         }
         self.print_call_post(base_args)
     }
@@ -1964,12 +1964,12 @@ fn print_expr_binary(&mut self,
                          lhs: &ast::Expr,
                          rhs: &ast::Expr) -> io::Result<()> {
         if self.check_expr_bin_needs_paren(lhs, op) {
-            try!(self.print_expr_maybe_paren(lhs));
+            self.print_expr_maybe_paren(lhs)?;
         } else {
-            try!(self.print_expr(lhs));
+            self.print_expr(lhs)?;
         }
-        try!(space(&mut self.s));
-        try!(self.word_space(op.node.to_string()));
+        space(&mut self.s)?;
+        self.word_space(op.node.to_string())?;
         if self.check_expr_bin_needs_paren(rhs, op) {
             self.print_expr_maybe_paren(rhs)
         } else {
@@ -1980,15 +1980,15 @@ fn print_expr_binary(&mut self,
     fn print_expr_unary(&mut self,
                         op: ast::UnOp,
                         expr: &ast::Expr) -> io::Result<()> {
-        try!(word(&mut self.s, ast::UnOp::to_string(op)));
+        word(&mut self.s, ast::UnOp::to_string(op))?;
         self.print_expr_maybe_paren(expr)
     }
 
     fn print_expr_addr_of(&mut self,
                           mutability: ast::Mutability,
                           expr: &ast::Expr) -> io::Result<()> {
-        try!(word(&mut self.s, "&"));
-        try!(self.print_mutability(mutability));
+        word(&mut self.s, "&")?;
+        self.print_mutability(mutability)?;
         self.print_expr_maybe_paren(expr)
     }
 
@@ -1999,271 +1999,271 @@ pub fn print_expr(&mut self, expr: &ast::Expr) -> io::Result<()> {
     fn print_expr_outer_attr_style(&mut self,
                                   expr: &ast::Expr,
                                   is_inline: bool) -> io::Result<()> {
-        try!(self.maybe_print_comment(expr.span.lo));
+        self.maybe_print_comment(expr.span.lo)?;
 
         let attrs = &expr.attrs;
         if is_inline {
-            try!(self.print_outer_attributes_inline(attrs));
+            self.print_outer_attributes_inline(attrs)?;
         } else {
-            try!(self.print_outer_attributes(attrs));
+            self.print_outer_attributes(attrs)?;
         }
 
-        try!(self.ibox(INDENT_UNIT));
-        try!(self.ann.pre(self, NodeExpr(expr)));
+        self.ibox(INDENT_UNIT)?;
+        self.ann.pre(self, NodeExpr(expr))?;
         match expr.node {
             ast::ExprKind::Box(ref expr) => {
-                try!(self.word_space("box"));
-                try!(self.print_expr(expr));
+                self.word_space("box")?;
+                self.print_expr(expr)?;
             }
             ast::ExprKind::InPlace(ref place, ref expr) => {
-                try!(self.print_expr_in_place(place, expr));
+                self.print_expr_in_place(place, expr)?;
             }
             ast::ExprKind::Vec(ref exprs) => {
-                try!(self.print_expr_vec(&exprs[..], attrs));
+                self.print_expr_vec(&exprs[..], attrs)?;
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
-                try!(self.print_expr_repeat(&element, &count, attrs));
+                self.print_expr_repeat(&element, &count, attrs)?;
             }
             ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
-                try!(self.print_expr_struct(path, &fields[..], wth, attrs));
+                self.print_expr_struct(path, &fields[..], wth, attrs)?;
             }
             ast::ExprKind::Tup(ref exprs) => {
-                try!(self.print_expr_tup(&exprs[..], attrs));
+                self.print_expr_tup(&exprs[..], attrs)?;
             }
             ast::ExprKind::Call(ref func, ref args) => {
-                try!(self.print_expr_call(&func, &args[..]));
+                self.print_expr_call(&func, &args[..])?;
             }
             ast::ExprKind::MethodCall(ident, ref tys, ref args) => {
-                try!(self.print_expr_method_call(ident, &tys[..], &args[..]));
+                self.print_expr_method_call(ident, &tys[..], &args[..])?;
             }
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                try!(self.print_expr_binary(op, &lhs, &rhs));
+                self.print_expr_binary(op, &lhs, &rhs)?;
             }
             ast::ExprKind::Unary(op, ref expr) => {
-                try!(self.print_expr_unary(op, &expr));
+                self.print_expr_unary(op, &expr)?;
             }
             ast::ExprKind::AddrOf(m, ref expr) => {
-                try!(self.print_expr_addr_of(m, &expr));
+                self.print_expr_addr_of(m, &expr)?;
             }
             ast::ExprKind::Lit(ref lit) => {
-                try!(self.print_literal(&lit));
+                self.print_literal(&lit)?;
             }
             ast::ExprKind::Cast(ref expr, ref ty) => {
                 if let ast::ExprKind::Cast(..) = expr.node {
-                    try!(self.print_expr(&expr));
+                    self.print_expr(&expr)?;
                 } else {
-                    try!(self.print_expr_maybe_paren(&expr));
+                    self.print_expr_maybe_paren(&expr)?;
                 }
-                try!(space(&mut self.s));
-                try!(self.word_space("as"));
-                try!(self.print_type(&ty));
+                space(&mut self.s)?;
+                self.word_space("as")?;
+                self.print_type(&ty)?;
             }
             ast::ExprKind::Type(ref expr, ref ty) => {
-                try!(self.print_expr(&expr));
-                try!(self.word_space(":"));
-                try!(self.print_type(&ty));
+                self.print_expr(&expr)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
             }
             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                try!(self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e)));
+                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                try!(self.print_if_let(&pat, &expr, &blk, elseopt.as_ref().map(|e| &**e)));
+                self.print_if_let(&pat, &expr, &blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::While(ref test, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(self.word_space(":"));
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
                 }
-                try!(self.head("while"));
-                try!(self.print_expr(&test));
-                try!(space(&mut self.s));
-                try!(self.print_block_with_attrs(&blk, attrs));
+                self.head("while")?;
+                self.print_expr(&test)?;
+                space(&mut self.s)?;
+                self.print_block_with_attrs(&blk, attrs)?;
             }
             ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(self.word_space(":"));
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
                 }
-                try!(self.head("while let"));
-                try!(self.print_pat(&pat));
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_expr(&expr));
-                try!(space(&mut self.s));
-                try!(self.print_block_with_attrs(&blk, attrs));
+                self.head("while let")?;
+                self.print_pat(&pat)?;
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_expr(&expr)?;
+                space(&mut self.s)?;
+                self.print_block_with_attrs(&blk, attrs)?;
             }
             ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(self.word_space(":"));
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
                 }
-                try!(self.head("for"));
-                try!(self.print_pat(&pat));
-                try!(space(&mut self.s));
-                try!(self.word_space("in"));
-                try!(self.print_expr(&iter));
-                try!(space(&mut self.s));
-                try!(self.print_block_with_attrs(&blk, attrs));
+                self.head("for")?;
+                self.print_pat(&pat)?;
+                space(&mut self.s)?;
+                self.word_space("in")?;
+                self.print_expr(&iter)?;
+                space(&mut self.s)?;
+                self.print_block_with_attrs(&blk, attrs)?;
             }
             ast::ExprKind::Loop(ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(self.word_space(":"));
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
                 }
-                try!(self.head("loop"));
-                try!(space(&mut self.s));
-                try!(self.print_block_with_attrs(&blk, attrs));
+                self.head("loop")?;
+                space(&mut self.s)?;
+                self.print_block_with_attrs(&blk, attrs)?;
             }
             ast::ExprKind::Match(ref expr, ref arms) => {
-                try!(self.cbox(INDENT_UNIT));
-                try!(self.ibox(4));
-                try!(self.word_nbsp("match"));
-                try!(self.print_expr(&expr));
-                try!(space(&mut self.s));
-                try!(self.bopen());
-                try!(self.print_inner_attributes_no_trailing_hardbreak(attrs));
+                self.cbox(INDENT_UNIT)?;
+                self.ibox(4)?;
+                self.word_nbsp("match")?;
+                self.print_expr(&expr)?;
+                space(&mut self.s)?;
+                self.bopen()?;
+                self.print_inner_attributes_no_trailing_hardbreak(attrs)?;
                 for arm in arms {
-                    try!(self.print_arm(arm));
+                    self.print_arm(arm)?;
                 }
-                try!(self.bclose_(expr.span, INDENT_UNIT));
+                self.bclose_(expr.span, INDENT_UNIT)?;
             }
             ast::ExprKind::Closure(capture_clause, ref decl, ref body, _) => {
-                try!(self.print_capture_clause(capture_clause));
+                self.print_capture_clause(capture_clause)?;
 
-                try!(self.print_fn_block_args(&decl));
-                try!(space(&mut self.s));
-                try!(self.print_expr(body));
-                try!(self.end()); // need to close a box
+                self.print_fn_block_args(&decl)?;
+                space(&mut self.s)?;
+                self.print_expr(body)?;
+                self.end()?; // need to close a box
 
                 // a box will be closed by print_expr, but we didn't want an overall
                 // wrapper so we closed the corresponding opening. so create an
                 // empty box to satisfy the close.
-                try!(self.ibox(0));
+                self.ibox(0)?;
             }
             ast::ExprKind::Block(ref blk) => {
                 // containing cbox, will be closed by print-block at }
-                try!(self.cbox(INDENT_UNIT));
+                self.cbox(INDENT_UNIT)?;
                 // head-box, will be closed by print-block after {
-                try!(self.ibox(0));
-                try!(self.print_block_with_attrs(&blk, attrs));
+                self.ibox(0)?;
+                self.print_block_with_attrs(&blk, attrs)?;
             }
             ast::ExprKind::Assign(ref lhs, ref rhs) => {
-                try!(self.print_expr(&lhs));
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_expr(&rhs));
+                self.print_expr(&lhs)?;
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_expr(&rhs)?;
             }
             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                try!(self.print_expr(&lhs));
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, op.node.to_string()));
-                try!(self.word_space("="));
-                try!(self.print_expr(&rhs));
+                self.print_expr(&lhs)?;
+                space(&mut self.s)?;
+                word(&mut self.s, op.node.to_string())?;
+                self.word_space("=")?;
+                self.print_expr(&rhs)?;
             }
             ast::ExprKind::Field(ref expr, id) => {
-                try!(self.print_expr(&expr));
-                try!(word(&mut self.s, "."));
-                try!(self.print_ident(id.node));
+                self.print_expr(&expr)?;
+                word(&mut self.s, ".")?;
+                self.print_ident(id.node)?;
             }
             ast::ExprKind::TupField(ref expr, id) => {
-                try!(self.print_expr(&expr));
-                try!(word(&mut self.s, "."));
-                try!(self.print_usize(id.node));
+                self.print_expr(&expr)?;
+                word(&mut self.s, ".")?;
+                self.print_usize(id.node)?;
             }
             ast::ExprKind::Index(ref expr, ref index) => {
-                try!(self.print_expr(&expr));
-                try!(word(&mut self.s, "["));
-                try!(self.print_expr(&index));
-                try!(word(&mut self.s, "]"));
+                self.print_expr(&expr)?;
+                word(&mut self.s, "[")?;
+                self.print_expr(&index)?;
+                word(&mut self.s, "]")?;
             }
             ast::ExprKind::Range(ref start, ref end, limits) => {
                 if let &Some(ref e) = start {
-                    try!(self.print_expr(&e));
+                    self.print_expr(&e)?;
                 }
                 if limits == ast::RangeLimits::HalfOpen {
-                    try!(word(&mut self.s, ".."));
+                    word(&mut self.s, "..")?;
                 } else {
-                    try!(word(&mut self.s, "..."));
+                    word(&mut self.s, "...")?;
                 }
                 if let &Some(ref e) = end {
-                    try!(self.print_expr(&e));
+                    self.print_expr(&e)?;
                 }
             }
             ast::ExprKind::Path(None, ref path) => {
-                try!(self.print_path(path, true, 0, false))
+                self.print_path(path, true, 0, false)?
             }
             ast::ExprKind::Path(Some(ref qself), ref path) => {
-                try!(self.print_qpath(path, qself, true))
+                self.print_qpath(path, qself, true)?
             }
             ast::ExprKind::Break(opt_ident, ref opt_expr) => {
-                try!(word(&mut self.s, "break"));
-                try!(space(&mut self.s));
+                word(&mut self.s, "break")?;
+                space(&mut self.s)?;
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(space(&mut self.s));
+                    self.print_ident(ident.node)?;
+                    space(&mut self.s)?;
                 }
                 if let Some(ref expr) = *opt_expr {
-                    try!(self.print_expr(expr));
-                    try!(space(&mut self.s));
+                    self.print_expr(expr)?;
+                    space(&mut self.s)?;
                 }
             }
             ast::ExprKind::Continue(opt_ident) => {
-                try!(word(&mut self.s, "continue"));
-                try!(space(&mut self.s));
+                word(&mut self.s, "continue")?;
+                space(&mut self.s)?;
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident.node));
-                    try!(space(&mut self.s))
+                    self.print_ident(ident.node)?;
+                    space(&mut self.s)?
                 }
             }
             ast::ExprKind::Ret(ref result) => {
-                try!(word(&mut self.s, "return"));
+                word(&mut self.s, "return")?;
                 match *result {
                     Some(ref expr) => {
-                        try!(word(&mut self.s, " "));
-                        try!(self.print_expr(&expr));
+                        word(&mut self.s, " ")?;
+                        self.print_expr(&expr)?;
                     }
                     _ => ()
                 }
             }
             ast::ExprKind::InlineAsm(ref a) => {
-                try!(word(&mut self.s, "asm!"));
-                try!(self.popen());
-                try!(self.print_string(&a.asm.as_str(), a.asm_str_style));
-                try!(self.word_space(":"));
+                word(&mut self.s, "asm!")?;
+                self.popen()?;
+                self.print_string(&a.asm.as_str(), a.asm_str_style)?;
+                self.word_space(":")?;
 
-                try!(self.commasep(Inconsistent, &a.outputs, |s, out| {
+                self.commasep(Inconsistent, &a.outputs, |s, out| {
                     let constraint = out.constraint.as_str();
                     let mut ch = constraint.chars();
                     match ch.next() {
                         Some('=') if out.is_rw => {
-                            try!(s.print_string(&format!("+{}", ch.as_str()),
-                                           ast::StrStyle::Cooked))
+                            s.print_string(&format!("+{}", ch.as_str()),
+                                           ast::StrStyle::Cooked)?
                         }
-                        _ => try!(s.print_string(&constraint, ast::StrStyle::Cooked))
+                        _ => s.print_string(&constraint, ast::StrStyle::Cooked)?
                     }
-                    try!(s.popen());
-                    try!(s.print_expr(&out.expr));
-                    try!(s.pclose());
+                    s.popen()?;
+                    s.print_expr(&out.expr)?;
+                    s.pclose()?;
                     Ok(())
-                }));
-                try!(space(&mut self.s));
-                try!(self.word_space(":"));
-
-                try!(self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
-                    try!(s.print_string(&co.as_str(), ast::StrStyle::Cooked));
-                    try!(s.popen());
-                    try!(s.print_expr(&o));
-                    try!(s.pclose());
+                })?;
+                space(&mut self.s)?;
+                self.word_space(":")?;
+
+                self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
+                    s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
+                    s.popen()?;
+                    s.print_expr(&o)?;
+                    s.pclose()?;
                     Ok(())
-                }));
-                try!(space(&mut self.s));
-                try!(self.word_space(":"));
+                })?;
+                space(&mut self.s)?;
+                self.word_space(":")?;
 
-                try!(self.commasep(Inconsistent, &a.clobbers,
+                self.commasep(Inconsistent, &a.clobbers,
                                    |s, co| {
-                    try!(s.print_string(&co.as_str(), ast::StrStyle::Cooked));
+                    s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
                     Ok(())
-                }));
+                })?;
 
                 let mut options = vec![];
                 if a.volatile {
@@ -2277,44 +2277,44 @@ fn print_expr_outer_attr_style(&mut self,
                 }
 
                 if !options.is_empty() {
-                    try!(space(&mut self.s));
-                    try!(self.word_space(":"));
-                    try!(self.commasep(Inconsistent, &options,
+                    space(&mut self.s)?;
+                    self.word_space(":")?;
+                    self.commasep(Inconsistent, &options,
                                   |s, &co| {
-                                      try!(s.print_string(co, ast::StrStyle::Cooked));
+                                      s.print_string(co, ast::StrStyle::Cooked)?;
                                       Ok(())
-                                  }));
+                                  })?;
                 }
 
-                try!(self.pclose());
+                self.pclose()?;
             }
-            ast::ExprKind::Mac(ref m) => try!(self.print_mac(m, token::Paren)),
+            ast::ExprKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
             ast::ExprKind::Paren(ref e) => {
-                try!(self.popen());
-                try!(self.print_inner_attributes_inline(attrs));
-                try!(self.print_expr(&e));
-                try!(self.pclose());
+                self.popen()?;
+                self.print_inner_attributes_inline(attrs)?;
+                self.print_expr(&e)?;
+                self.pclose()?;
             },
             ast::ExprKind::Try(ref e) => {
-                try!(self.print_expr(e));
-                try!(word(&mut self.s, "?"))
+                self.print_expr(e)?;
+                word(&mut self.s, "?")?
             }
         }
-        try!(self.ann.post(self, NodeExpr(expr)));
+        self.ann.post(self, NodeExpr(expr))?;
         self.end()
     }
 
     pub fn print_local_decl(&mut self, loc: &ast::Local) -> io::Result<()> {
-        try!(self.print_pat(&loc.pat));
+        self.print_pat(&loc.pat)?;
         if let Some(ref ty) = loc.ty {
-            try!(self.word_space(":"));
-            try!(self.print_type(&ty));
+            self.word_space(":")?;
+            self.print_type(&ty)?;
         }
         Ok(())
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        try!(word(&mut self.s, &ident.name.as_str()));
+        word(&mut self.s, &ident.name.as_str())?;
         self.ann.post(self, NodeIdent(&ident))
     }
 
@@ -2323,15 +2323,15 @@ pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
-        try!(word(&mut self.s, &name.as_str()));
+        word(&mut self.s, &name.as_str())?;
         self.ann.post(self, NodeName(&name))
     }
 
     pub fn print_for_decl(&mut self, loc: &ast::Local,
                           coll: &ast::Expr) -> io::Result<()> {
-        try!(self.print_local_decl(loc));
-        try!(space(&mut self.s));
-        try!(self.word_space("in"));
+        self.print_local_decl(loc)?;
+        space(&mut self.s)?;
+        self.word_space("in")?;
         self.print_expr(coll)
     }
 
@@ -2342,7 +2342,7 @@ fn print_path(&mut self,
                   defaults_to_global: bool)
                   -> io::Result<()>
     {
-        try!(self.maybe_print_comment(path.span.lo));
+        self.maybe_print_comment(path.span.lo)?;
 
         let mut segments = path.segments[..path.segments.len()-depth].iter();
         if defaults_to_global && path.is_global() {
@@ -2350,13 +2350,13 @@ fn print_path(&mut self,
         }
         for (i, segment) in segments.enumerate() {
             if i > 0 {
-                try!(word(&mut self.s, "::"))
+                word(&mut self.s, "::")?
             }
             if segment.identifier.name != keywords::CrateRoot.name() &&
                segment.identifier.name != "$crate" {
-                try!(self.print_ident(segment.identifier));
+                self.print_ident(segment.identifier)?;
                 if let Some(ref parameters) = segment.parameters {
-                    try!(self.print_path_parameters(parameters, colons_before_params));
+                    self.print_path_parameters(parameters, colons_before_params)?;
                 }
             }
         }
@@ -2370,18 +2370,18 @@ fn print_qpath(&mut self,
                    colons_before_params: bool)
                    -> io::Result<()>
     {
-        try!(word(&mut self.s, "<"));
-        try!(self.print_type(&qself.ty));
+        word(&mut self.s, "<")?;
+        self.print_type(&qself.ty)?;
         if qself.position > 0 {
-            try!(space(&mut self.s));
-            try!(self.word_space("as"));
+            space(&mut self.s)?;
+            self.word_space("as")?;
             let depth = path.segments.len() - qself.position;
-            try!(self.print_path(&path, false, depth, false));
+            self.print_path(&path, false, depth, false)?;
         }
-        try!(word(&mut self.s, ">"));
-        try!(word(&mut self.s, "::"));
+        word(&mut self.s, ">")?;
+        word(&mut self.s, "::")?;
         let item_segment = path.segments.last().unwrap();
-        try!(self.print_ident(item_segment.identifier));
+        self.print_ident(item_segment.identifier)?;
         match item_segment.parameters {
             Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params),
             None => Ok(()),
@@ -2394,59 +2394,59 @@ fn print_path_parameters(&mut self,
                              -> io::Result<()>
     {
         if colons_before_params {
-            try!(word(&mut self.s, "::"))
+            word(&mut self.s, "::")?
         }
 
         match *parameters {
             ast::PathParameters::AngleBracketed(ref data) => {
-                try!(word(&mut self.s, "<"));
+                word(&mut self.s, "<")?;
 
                 let mut comma = false;
                 for lifetime in &data.lifetimes {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.print_lifetime(lifetime));
+                    self.print_lifetime(lifetime)?;
                     comma = true;
                 }
 
                 if !data.types.is_empty() {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.commasep(
+                    self.commasep(
                         Inconsistent,
                         &data.types,
-                        |s, ty| s.print_type(&ty)));
+                        |s, ty| s.print_type(&ty))?;
                         comma = true;
                 }
 
                 for binding in data.bindings.iter() {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.print_ident(binding.ident));
-                    try!(space(&mut self.s));
-                    try!(self.word_space("="));
-                    try!(self.print_type(&binding.ty));
+                    self.print_ident(binding.ident)?;
+                    space(&mut self.s)?;
+                    self.word_space("=")?;
+                    self.print_type(&binding.ty)?;
                     comma = true;
                 }
 
-                try!(word(&mut self.s, ">"))
+                word(&mut self.s, ">")?
             }
 
             ast::PathParameters::Parenthesized(ref data) => {
-                try!(word(&mut self.s, "("));
-                try!(self.commasep(
+                word(&mut self.s, "(")?;
+                self.commasep(
                     Inconsistent,
                     &data.inputs,
-                    |s, ty| s.print_type(&ty)));
-                try!(word(&mut self.s, ")"));
+                    |s, ty| s.print_type(&ty))?;
+                word(&mut self.s, ")")?;
 
                 if let Some(ref ty) = data.output {
-                    try!(self.space_if_not_bol());
-                    try!(self.word_space("->"));
-                    try!(self.print_type(&ty));
+                    self.space_if_not_bol()?;
+                    self.word_space("->")?;
+                    self.print_type(&ty)?;
                 }
             }
         }
@@ -2455,133 +2455,133 @@ fn print_path_parameters(&mut self,
     }
 
     pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
-        try!(self.maybe_print_comment(pat.span.lo));
-        try!(self.ann.pre(self, NodePat(pat)));
+        self.maybe_print_comment(pat.span.lo)?;
+        self.ann.pre(self, NodePat(pat))?;
         /* Pat isn't normalized, but the beauty of it
          is that it doesn't matter */
         match pat.node {
-            PatKind::Wild => try!(word(&mut self.s, "_")),
+            PatKind::Wild => word(&mut self.s, "_")?,
             PatKind::Ident(binding_mode, ref path1, ref sub) => {
                 match binding_mode {
                     ast::BindingMode::ByRef(mutbl) => {
-                        try!(self.word_nbsp("ref"));
-                        try!(self.print_mutability(mutbl));
+                        self.word_nbsp("ref")?;
+                        self.print_mutability(mutbl)?;
                     }
                     ast::BindingMode::ByValue(ast::Mutability::Immutable) => {}
                     ast::BindingMode::ByValue(ast::Mutability::Mutable) => {
-                        try!(self.word_nbsp("mut"));
+                        self.word_nbsp("mut")?;
                     }
                 }
-                try!(self.print_ident(path1.node));
+                self.print_ident(path1.node)?;
                 if let Some(ref p) = *sub {
-                    try!(word(&mut self.s, "@"));
-                    try!(self.print_pat(&p));
+                    word(&mut self.s, "@")?;
+                    self.print_pat(&p)?;
                 }
             }
             PatKind::TupleStruct(ref path, ref elts, ddpos) => {
-                try!(self.print_path(path, true, 0, false));
-                try!(self.popen());
+                self.print_path(path, true, 0, false)?;
+                self.popen()?;
                 if let Some(ddpos) = ddpos {
-                    try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
                     if ddpos != 0 {
-                        try!(self.word_space(","));
+                        self.word_space(",")?;
                     }
-                    try!(word(&mut self.s, ".."));
+                    word(&mut self.s, "..")?;
                     if ddpos != elts.len() {
-                        try!(word(&mut self.s, ","));
-                        try!(self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)));
+                        word(&mut self.s, ",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
                     }
                 } else {
-                    try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
                 }
-                try!(self.pclose());
+                self.pclose()?;
             }
             PatKind::Path(None, ref path) => {
-                try!(self.print_path(path, true, 0, false));
+                self.print_path(path, true, 0, false)?;
             }
             PatKind::Path(Some(ref qself), ref path) => {
-                try!(self.print_qpath(path, qself, false));
+                self.print_qpath(path, qself, false)?;
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                try!(self.print_path(path, true, 0, false));
-                try!(self.nbsp());
-                try!(self.word_space("{"));
-                try!(self.commasep_cmnt(
+                self.print_path(path, true, 0, false)?;
+                self.nbsp()?;
+                self.word_space("{")?;
+                self.commasep_cmnt(
                     Consistent, &fields[..],
                     |s, f| {
-                        try!(s.cbox(INDENT_UNIT));
+                        s.cbox(INDENT_UNIT)?;
                         if !f.node.is_shorthand {
-                            try!(s.print_ident(f.node.ident));
-                            try!(s.word_nbsp(":"));
+                            s.print_ident(f.node.ident)?;
+                            s.word_nbsp(":")?;
                         }
-                        try!(s.print_pat(&f.node.pat));
+                        s.print_pat(&f.node.pat)?;
                         s.end()
                     },
-                    |f| f.node.pat.span));
+                    |f| f.node.pat.span)?;
                 if etc {
-                    if !fields.is_empty() { try!(self.word_space(",")); }
-                    try!(word(&mut self.s, ".."));
+                    if !fields.is_empty() { self.word_space(",")?; }
+                    word(&mut self.s, "..")?;
                 }
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, "}"));
+                space(&mut self.s)?;
+                word(&mut self.s, "}")?;
             }
             PatKind::Tuple(ref elts, ddpos) => {
-                try!(self.popen());
+                self.popen()?;
                 if let Some(ddpos) = ddpos {
-                    try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
                     if ddpos != 0 {
-                        try!(self.word_space(","));
+                        self.word_space(",")?;
                     }
-                    try!(word(&mut self.s, ".."));
+                    word(&mut self.s, "..")?;
                     if ddpos != elts.len() {
-                        try!(word(&mut self.s, ","));
-                        try!(self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)));
+                        word(&mut self.s, ",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
                     }
                 } else {
-                    try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
                     if elts.len() == 1 {
-                        try!(word(&mut self.s, ","));
+                        word(&mut self.s, ",")?;
                     }
                 }
-                try!(self.pclose());
+                self.pclose()?;
             }
             PatKind::Box(ref inner) => {
-                try!(word(&mut self.s, "box "));
-                try!(self.print_pat(&inner));
+                word(&mut self.s, "box ")?;
+                self.print_pat(&inner)?;
             }
             PatKind::Ref(ref inner, mutbl) => {
-                try!(word(&mut self.s, "&"));
+                word(&mut self.s, "&")?;
                 if mutbl == ast::Mutability::Mutable {
-                    try!(word(&mut self.s, "mut "));
+                    word(&mut self.s, "mut ")?;
                 }
-                try!(self.print_pat(&inner));
+                self.print_pat(&inner)?;
             }
-            PatKind::Lit(ref e) => try!(self.print_expr(&**e)),
+            PatKind::Lit(ref e) => self.print_expr(&**e)?,
             PatKind::Range(ref begin, ref end) => {
-                try!(self.print_expr(&begin));
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, "..."));
-                try!(self.print_expr(&end));
+                self.print_expr(&begin)?;
+                space(&mut self.s)?;
+                word(&mut self.s, "...")?;
+                self.print_expr(&end)?;
             }
             PatKind::Slice(ref before, ref slice, ref after) => {
-                try!(word(&mut self.s, "["));
-                try!(self.commasep(Inconsistent,
+                word(&mut self.s, "[")?;
+                self.commasep(Inconsistent,
                                    &before[..],
-                                   |s, p| s.print_pat(&p)));
+                                   |s, p| s.print_pat(&p))?;
                 if let Some(ref p) = *slice {
-                    if !before.is_empty() { try!(self.word_space(",")); }
+                    if !before.is_empty() { self.word_space(",")?; }
                     if p.node != PatKind::Wild {
-                        try!(self.print_pat(&p));
+                        self.print_pat(&p)?;
                     }
-                    try!(word(&mut self.s, ".."));
-                    if !after.is_empty() { try!(self.word_space(",")); }
+                    word(&mut self.s, "..")?;
+                    if !after.is_empty() { self.word_space(",")?; }
                 }
-                try!(self.commasep(Inconsistent,
+                self.commasep(Inconsistent,
                                    &after[..],
-                                   |s, p| s.print_pat(&p)));
-                try!(word(&mut self.s, "]"));
+                                   |s, p| s.print_pat(&p))?;
+                word(&mut self.s, "]")?;
             }
-            PatKind::Mac(ref m) => try!(self.print_mac(m, token::Paren)),
+            PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
         }
         self.ann.post(self, NodePat(pat))
     }
@@ -2590,44 +2590,44 @@ fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
         // I have no idea why this check is necessary, but here it
         // is :(
         if arm.attrs.is_empty() {
-            try!(space(&mut self.s));
+            space(&mut self.s)?;
         }
-        try!(self.cbox(INDENT_UNIT));
-        try!(self.ibox(0));
-        try!(self.maybe_print_comment(arm.pats[0].span.lo));
-        try!(self.print_outer_attributes(&arm.attrs));
+        self.cbox(INDENT_UNIT)?;
+        self.ibox(0)?;
+        self.maybe_print_comment(arm.pats[0].span.lo)?;
+        self.print_outer_attributes(&arm.attrs)?;
         let mut first = true;
         for p in &arm.pats {
             if first {
                 first = false;
             } else {
-                try!(space(&mut self.s));
-                try!(self.word_space("|"));
+                space(&mut self.s)?;
+                self.word_space("|")?;
             }
-            try!(self.print_pat(&p));
+            self.print_pat(&p)?;
         }
-        try!(space(&mut self.s));
+        space(&mut self.s)?;
         if let Some(ref e) = arm.guard {
-            try!(self.word_space("if"));
-            try!(self.print_expr(&e));
-            try!(space(&mut self.s));
+            self.word_space("if")?;
+            self.print_expr(&e)?;
+            space(&mut self.s)?;
         }
-        try!(self.word_space("=>"));
+        self.word_space("=>")?;
 
         match arm.body.node {
             ast::ExprKind::Block(ref blk) => {
                 // the block will close the pattern's ibox
-                try!(self.print_block_unclosed_indent(&blk, INDENT_UNIT));
+                self.print_block_unclosed_indent(&blk, INDENT_UNIT)?;
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
-                    try!(word(&mut self.s, ","));
+                    word(&mut self.s, ",")?;
                 }
             }
             _ => {
-                try!(self.end()); // close the ibox for the pattern
-                try!(self.print_expr(&arm.body));
-                try!(word(&mut self.s, ","));
+                self.end()?; // close the ibox for the pattern
+                self.print_expr(&arm.body)?;
+                word(&mut self.s, ",")?;
             }
         }
         self.end() // close enclosing cbox
@@ -2636,19 +2636,19 @@ fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) -> io::Result<()> {
         match explicit_self.node {
             SelfKind::Value(m) => {
-                try!(self.print_mutability(m));
+                self.print_mutability(m)?;
                 word(&mut self.s, "self")
             }
             SelfKind::Region(ref lt, m) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.print_opt_lifetime(lt));
-                try!(self.print_mutability(m));
+                word(&mut self.s, "&")?;
+                self.print_opt_lifetime(lt)?;
+                self.print_mutability(m)?;
                 word(&mut self.s, "self")
             }
             SelfKind::Explicit(ref typ, m) => {
-                try!(self.print_mutability(m));
-                try!(word(&mut self.s, "self"));
-                try!(self.word_space(":"));
+                self.print_mutability(m)?;
+                word(&mut self.s, "self")?;
+                self.word_space(":")?;
                 self.print_type(&typ)
             }
         }
@@ -2662,25 +2662,25 @@ pub fn print_fn(&mut self,
                     name: Option<ast::Ident>,
                     generics: &ast::Generics,
                     vis: &ast::Visibility) -> io::Result<()> {
-        try!(self.print_fn_header_info(unsafety, constness, abi, vis));
+        self.print_fn_header_info(unsafety, constness, abi, vis)?;
 
         if let Some(name) = name {
-            try!(self.nbsp());
-            try!(self.print_ident(name));
+            self.nbsp()?;
+            self.print_ident(name)?;
         }
-        try!(self.print_generics(generics));
-        try!(self.print_fn_args_and_ret(decl));
+        self.print_generics(generics)?;
+        self.print_fn_args_and_ret(decl)?;
         self.print_where_clause(&generics.where_clause)
     }
 
     pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl)
         -> io::Result<()> {
-        try!(self.popen());
-        try!(self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false)));
+        self.popen()?;
+        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
         if decl.variadic {
-            try!(word(&mut self.s, ", ..."));
+            word(&mut self.s, ", ...")?;
         }
-        try!(self.pclose());
+        self.pclose()?;
 
         self.print_fn_output(decl)
     }
@@ -2689,19 +2689,19 @@ pub fn print_fn_block_args(
             &mut self,
             decl: &ast::FnDecl)
             -> io::Result<()> {
-        try!(word(&mut self.s, "|"));
-        try!(self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true)));
-        try!(word(&mut self.s, "|"));
+        word(&mut self.s, "|")?;
+        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+        word(&mut self.s, "|")?;
 
         if let ast::FunctionRetTy::Default(..) = decl.output {
             return Ok(());
         }
 
-        try!(self.space_if_not_bol());
-        try!(self.word_space("->"));
+        self.space_if_not_bol()?;
+        self.word_space("->")?;
         match decl.output {
             ast::FunctionRetTy::Ty(ref ty) => {
-                try!(self.print_type(&ty));
+                self.print_type(&ty)?;
                 self.maybe_print_comment(ty.span.lo)
             }
             ast::FunctionRetTy::Default(..) => unreachable!(),
@@ -2721,28 +2721,28 @@ pub fn print_bounds(&mut self,
                         bounds: &[ast::TyParamBound])
                         -> io::Result<()> {
         if !bounds.is_empty() {
-            try!(word(&mut self.s, prefix));
+            word(&mut self.s, prefix)?;
             let mut first = true;
             for bound in bounds {
-                try!(self.nbsp());
+                self.nbsp()?;
                 if first {
                     first = false;
                 } else {
-                    try!(self.word_space("+"));
+                    self.word_space("+")?;
                 }
 
-                try!(match *bound {
+                (match *bound {
                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
                         self.print_poly_trait_ref(tref)
                     }
                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
-                        try!(word(&mut self.s, "?"));
+                        word(&mut self.s, "?")?;
                         self.print_poly_trait_ref(tref)
                     }
                     RegionTyParamBound(ref lt) => {
                         self.print_lifetime(lt)
                     }
-                })
+                })?
             }
             Ok(())
         } else {
@@ -2762,14 +2762,14 @@ pub fn print_lifetime_bounds(&mut self,
                                  bounds: &[ast::Lifetime])
                                  -> io::Result<()>
     {
-        try!(self.print_lifetime(lifetime));
+        self.print_lifetime(lifetime)?;
         if !bounds.is_empty() {
-            try!(word(&mut self.s, ": "));
+            word(&mut self.s, ": ")?;
             for (i, bound) in bounds.iter().enumerate() {
                 if i != 0 {
-                    try!(word(&mut self.s, " + "));
+                    word(&mut self.s, " + ")?;
                 }
-                try!(self.print_lifetime(bound));
+                self.print_lifetime(bound)?;
             }
         }
         Ok(())
@@ -2784,37 +2784,37 @@ pub fn print_generics(&mut self,
             return Ok(());
         }
 
-        try!(word(&mut self.s, "<"));
+        word(&mut self.s, "<")?;
 
         let mut ints = Vec::new();
         for i in 0..total {
             ints.push(i);
         }
 
-        try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
+        self.commasep(Inconsistent, &ints[..], |s, &idx| {
             if idx < generics.lifetimes.len() {
                 let lifetime_def = &generics.lifetimes[idx];
-                try!(s.print_outer_attributes_inline(&lifetime_def.attrs));
+                s.print_outer_attributes_inline(&lifetime_def.attrs)?;
                 s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
             } else {
                 let idx = idx - generics.lifetimes.len();
                 let param = &generics.ty_params[idx];
                 s.print_ty_param(param)
             }
-        }));
+        })?;
 
-        try!(word(&mut self.s, ">"));
+        word(&mut self.s, ">")?;
         Ok(())
     }
 
     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
-        try!(self.print_outer_attributes_inline(&param.attrs));
-        try!(self.print_ident(param.ident));
-        try!(self.print_bounds(":", &param.bounds));
+        self.print_outer_attributes_inline(&param.attrs)?;
+        self.print_ident(param.ident)?;
+        self.print_bounds(":", &param.bounds)?;
         match param.default {
             Some(ref default) => {
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
+                space(&mut self.s)?;
+                self.word_space("=")?;
                 self.print_type(&default)
             }
             _ => Ok(())
@@ -2827,12 +2827,12 @@ pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
             return Ok(())
         }
 
-        try!(space(&mut self.s));
-        try!(self.word_space("where"));
+        space(&mut self.s)?;
+        self.word_space("where")?;
 
         for (i, predicate) in where_clause.predicates.iter().enumerate() {
             if i != 0 {
-                try!(self.word_space(","));
+                self.word_space(",")?;
             }
 
             match *predicate {
@@ -2840,20 +2840,20 @@ pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
                                                                              ref bounded_ty,
                                                                              ref bounds,
                                                                              ..}) => {
-                    try!(self.print_formal_lifetime_list(bound_lifetimes));
-                    try!(self.print_type(&bounded_ty));
-                    try!(self.print_bounds(":", bounds));
+                    self.print_formal_lifetime_list(bound_lifetimes)?;
+                    self.print_type(&bounded_ty)?;
+                    self.print_bounds(":", bounds)?;
                 }
                 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
                                                                                ref bounds,
                                                                                ..}) => {
-                    try!(self.print_lifetime_bounds(lifetime, bounds));
+                    self.print_lifetime_bounds(lifetime, bounds)?;
                 }
                 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
-                    try!(self.print_path(path, false, 0, false));
-                    try!(space(&mut self.s));
-                    try!(self.word_space("="));
-                    try!(self.print_type(&ty));
+                    self.print_path(path, false, 0, false)?;
+                    space(&mut self.s)?;
+                    self.word_space("=")?;
+                    self.print_type(&ty)?;
                 }
             }
         }
@@ -2864,39 +2864,39 @@ pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
         match vp.node {
             ast::ViewPathSimple(ident, ref path) => {
-                try!(self.print_path(path, false, 0, true));
+                self.print_path(path, false, 0, true)?;
 
                 if path.segments.last().unwrap().identifier.name !=
                         ident.name {
-                    try!(space(&mut self.s));
-                    try!(self.word_space("as"));
-                    try!(self.print_ident(ident));
+                    space(&mut self.s)?;
+                    self.word_space("as")?;
+                    self.print_ident(ident)?;
                 }
 
                 Ok(())
             }
 
             ast::ViewPathGlob(ref path) => {
-                try!(self.print_path(path, false, 0, true));
+                self.print_path(path, false, 0, true)?;
                 word(&mut self.s, "::*")
             }
 
             ast::ViewPathList(ref path, ref idents) => {
                 if path.segments.is_empty() {
-                    try!(word(&mut self.s, "{"));
+                    word(&mut self.s, "{")?;
                 } else {
-                    try!(self.print_path(path, false, 0, true));
-                    try!(word(&mut self.s, "::{"));
+                    self.print_path(path, false, 0, true)?;
+                    word(&mut self.s, "::{")?;
                 }
-                try!(self.commasep(Inconsistent, &idents[..], |s, w| {
-                    try!(s.print_ident(w.node.name));
+                self.commasep(Inconsistent, &idents[..], |s, w| {
+                    s.print_ident(w.node.name)?;
                     if let Some(ident) = w.node.rename {
-                        try!(space(&mut s.s));
-                        try!(s.word_space("as"));
-                        try!(s.print_ident(ident));
+                        space(&mut s.s)?;
+                        s.word_space("as")?;
+                        s.print_ident(ident)?;
                     }
                     Ok(())
-                }));
+                })?;
                 word(&mut self.s, "}")
             }
         }
@@ -2911,17 +2911,17 @@ pub fn print_mutability(&mut self,
     }
 
     pub fn print_mt(&mut self, mt: &ast::MutTy) -> io::Result<()> {
-        try!(self.print_mutability(mt.mutbl));
+        self.print_mutability(mt.mutbl)?;
         self.print_type(&mt.ty)
     }
 
     pub fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) -> io::Result<()> {
-        try!(self.ibox(INDENT_UNIT));
+        self.ibox(INDENT_UNIT)?;
         match input.ty.node {
-            ast::TyKind::Infer if is_closure => try!(self.print_pat(&input.pat)),
+            ast::TyKind::Infer if is_closure => self.print_pat(&input.pat)?,
             _ => {
                 if let Some(eself) = input.to_self() {
-                    try!(self.print_explicit_self(&eself));
+                    self.print_explicit_self(&eself)?;
                 } else {
                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node {
                         ident.node.name == keywords::Invalid.name()
@@ -2929,11 +2929,11 @@ pub fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) -> io::Result<()
                         false
                     };
                     if !invalid {
-                        try!(self.print_pat(&input.pat));
-                        try!(word(&mut self.s, ":"));
-                        try!(space(&mut self.s));
+                        self.print_pat(&input.pat)?;
+                        word(&mut self.s, ":")?;
+                        space(&mut self.s)?;
                     }
-                    try!(self.print_type(&input.ty));
+                    self.print_type(&input.ty)?;
                 }
             }
         }
@@ -2945,15 +2945,15 @@ pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> io::Result<()> {
             return Ok(());
         }
 
-        try!(self.space_if_not_bol());
-        try!(self.ibox(INDENT_UNIT));
-        try!(self.word_space("->"));
+        self.space_if_not_bol()?;
+        self.ibox(INDENT_UNIT)?;
+        self.word_space("->")?;
         match decl.output {
             ast::FunctionRetTy::Default(..) => unreachable!(),
             ast::FunctionRetTy::Ty(ref ty) =>
-                try!(self.print_type(&ty))
+                self.print_type(&ty)?
         }
-        try!(self.end());
+        self.end()?;
 
         match decl.output {
             ast::FunctionRetTy::Ty(ref output) => self.maybe_print_comment(output.span.lo),
@@ -2968,10 +2968,10 @@ pub fn print_ty_fn(&mut self,
                        name: Option<ast::Ident>,
                        generics: &ast::Generics)
                        -> io::Result<()> {
-        try!(self.ibox(INDENT_UNIT));
+        self.ibox(INDENT_UNIT)?;
         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
-            try!(word(&mut self.s, "for"));
-            try!(self.print_generics(generics));
+            word(&mut self.s, "for")?;
+            self.print_generics(generics)?;
         }
         let generics = ast::Generics {
             lifetimes: Vec::new(),
@@ -2982,13 +2982,13 @@ pub fn print_ty_fn(&mut self,
             },
             span: syntax_pos::DUMMY_SP,
         };
-        try!(self.print_fn(decl,
+        self.print_fn(decl,
                       unsafety,
                       ast::Constness::NotConst,
                       abi,
                       name,
                       &generics,
-                      &ast::Visibility::Inherited));
+                      &ast::Visibility::Inherited)?;
         self.end()
     }
 
@@ -3016,12 +3016,12 @@ pub fn print_remaining_comments(&mut self) -> io::Result<()> {
         // If there aren't any remaining comments, then we need to manually
         // make sure there is a line break at the end.
         if self.next_comment().is_none() {
-            try!(hardbreak(&mut self.s));
+            hardbreak(&mut self.s)?;
         }
         loop {
             match self.next_comment() {
                 Some(ref cmnt) => {
-                    try!(self.print_comment(cmnt));
+                    self.print_comment(cmnt)?;
                     self.cur_cmnt_and_lit.cur_cmnt += 1;
                 }
                 _ => break
@@ -3036,7 +3036,7 @@ pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
         match opt_abi {
             Some(Abi::Rust) => Ok(()),
             Some(abi) => {
-                try!(self.word_nbsp("extern"));
+                self.word_nbsp("extern")?;
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -3047,7 +3047,7 @@ pub fn print_extern_opt_abi(&mut self,
                                 opt_abi: Option<Abi>) -> io::Result<()> {
         match opt_abi {
             Some(abi) => {
-                try!(self.word_nbsp("extern"));
+                self.word_nbsp("extern")?;
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -3059,18 +3059,18 @@ pub fn print_fn_header_info(&mut self,
                                 constness: ast::Constness,
                                 abi: Abi,
                                 vis: &ast::Visibility) -> io::Result<()> {
-        try!(word(&mut self.s, &visibility_qualified(vis, "")));
+        word(&mut self.s, &visibility_qualified(vis, ""))?;
 
         match constness {
             ast::Constness::NotConst => {}
-            ast::Constness::Const => try!(self.word_nbsp("const"))
+            ast::Constness::Const => self.word_nbsp("const")?
         }
 
-        try!(self.print_unsafety(unsafety));
+        self.print_unsafety(unsafety)?;
 
         if abi != Abi::Rust {
-            try!(self.word_nbsp("extern"));
-            try!(self.word_nbsp(&abi.to_string()));
+            self.word_nbsp("extern")?;
+            self.word_nbsp(&abi.to_string())?;
         }
 
         word(&mut self.s, "fn")
index 0511b0d252b60b9fa2c0b4b6873ac0343a76a77c..2573690d15375b4abbf6e9be7bae7def1d5693b8 100644 (file)
@@ -15,7 +15,7 @@
 use syntax::codemap;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
 use syntax::ext::build::AstBuilder;
-use syntax::feature_gate::{self, emit_feature_err};
+use syntax::feature_gate;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -220,12 +220,6 @@ pub fn expand_derive(cx: &mut ExtCtxt,
                                  .filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap()))
                                  .next();
     if let Some((i, titem)) = macros_11_derive {
-        if !cx.ecfg.features.unwrap().proc_macro {
-            let issue = feature_gate::GateIssue::Language;
-            let msg = "custom derive macros are experimentally supported";
-            emit_feature_err(cx.parse_sess, "proc_macro", titem.span, issue, msg);
-        }
-
         let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
         let path = ast::Path::from_ident(titem.span, tname);
         let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
index e31b29d5cc1b435270cc4cf9949b7825e0b639f7..cbc2b2263f20ece774252694c4fb11d858cb66d2 100644 (file)
@@ -19,7 +19,6 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
-#![feature(proc_macro_lib)]
 #![feature(proc_macro_internals)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
index 5323ace79d8493f9366f45120ad657fdee18701e..c93e2c054d24044dcf566583d26afc02038b2b43 100644 (file)
@@ -17,7 +17,6 @@
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
 use syntax::parse::ParseSess;
-use syntax::feature_gate::Features;
 use syntax::fold::Folder;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
@@ -47,8 +46,7 @@ pub fn modify(sess: &ParseSess,
               is_proc_macro_crate: bool,
               is_test_crate: bool,
               num_crate_types: usize,
-              handler: &errors::Handler,
-              features: &Features) -> ast::Crate {
+              handler: &errors::Handler) -> ast::Crate {
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
     let mut cx = ExtCtxt::new(sess, ecfg, resolver);
 
@@ -66,12 +64,6 @@ pub fn modify(sess: &ParseSess,
 
     if !is_proc_macro_crate {
         return krate
-    } else if !features.proc_macro {
-        let mut err = handler.struct_err("the `proc-macro` crate type is \
-                                          experimental");
-        err.help("add #![feature(proc_macro)] to the crate attributes to \
-                  enable");
-        err.emit();
     }
 
     if num_crate_types > 1 {
index 7a04d377608d4ac2627230461d2e20ce41d7c623..f2d9119a7d15697c4db85ed47af161cec86c2e9a 100644 (file)
@@ -268,3 +268,22 @@ LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
     li.QuadPart += 1;
     return li;
 }
+
+#define DO_INT128_TEST !(defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && \
+    defined(__amd64__)
+
+#if DO_INT128_TEST
+
+unsigned __int128 identity(unsigned __int128 a) {
+    return a;
+}
+
+__int128 square(__int128 a) {
+    return a * a;
+}
+
+__int128 sub(__int128 a, __int128 b) {
+    return a - b;
+}
+
+#endif
index 9141b7245e35aa0d89465e01ce1b9ef887522cec..6135f49eb711be0c9a2e8c22bd6e84cb6b9fc444 100644 (file)
@@ -24,8 +24,8 @@ pub struct Bytes {
 // dependent alignment
 #[no_mangle]
 pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
-// CHECK: %arg1 = alloca [4 x i8]
 // CHECK: [[TMP:%.+]] = alloca i32
+// CHECK: %arg1 = alloca [4 x i8]
 // CHECK: store i32 %1, i32* [[TMP]]
 // CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %arg1 to i8*
 // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
@@ -38,8 +38,8 @@ pub struct Bytes {
 // dependent alignment
 #[no_mangle]
 pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
-// CHECK: %arg1 = alloca %Bytes
 // CHECK: [[TMP:%.+]] = alloca i32
+// CHECK: %arg1 = alloca %Bytes
 // CHECK: store i32 %1, i32* [[TMP]]
 // CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %arg1 to i8*
 // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
diff --git a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs
new file mode 100644 (file)
index 0000000..9dc4cf1
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This crate attempts to enumerate the various scenarios for how a
+// type can define fields and methods with various visiblities and
+// stabilities.
+//
+// The basic stability pattern in this file has four cases:
+// 1. no stability attribute at all
+// 2. a stable attribute (feature "unit_test")
+// 3. an unstable attribute that unit test declares (feature "unstable_declared")
+// 4. an unstable attribute that unit test fails to declare (feature "unstable_undeclared")
+//
+// This file also covers four kinds of visibility: private,
+// pub(module), pub(crate), and pub.
+//
+// However, since stability attributes can only be observed in
+// cross-crate linkage scenarios, there is little reason to take the
+// cross-product (4 stability cases * 4 visiblity cases), because the
+// first three visibility cases cannot be accessed outside this crate,
+// and therefore stability is only relevant when the visibility is pub
+// to the whole universe.
+//
+// (The only reason to do so would be if one were worried about the
+// compiler having some subtle bug where adding a stability attribute
+// introduces a privacy violation. As a way to provide evidence that
+// this is not occurring, I have put stability attributes on some
+// non-pub fields, marked with SILLY below)
+
+#![feature(staged_api)]
+#![feature(pub_restricted)]
+
+#![stable(feature = "unit_test", since = "0.0.0")]
+
+#[stable(feature = "unit_test", since = "0.0.0")]
+pub use m::{Record, Trait, Tuple};
+
+mod m {
+    #[derive(Default)]
+    #[stable(feature = "unit_test", since = "0.0.0")]
+    pub struct Record {
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        pub a_stable_pub: i32,
+        #[unstable(feature = "unstable_declared", issue = "38412")]
+        pub a_unstable_declared_pub: i32,
+        #[unstable(feature = "unstable_undeclared", issue = "38412")]
+        pub a_unstable_undeclared_pub: i32,
+        #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY
+        pub(crate) b_crate: i32,
+        #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY
+        pub(m) c_mod: i32,
+        #[stable(feature = "unit_test", since = "0.0.0")] // SILLY
+        d_priv: i32
+    }
+
+    #[derive(Default)]
+    #[stable(feature = "unit_test", since = "1.0.0")]
+    pub struct Tuple(
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        pub i32,
+        #[unstable(feature = "unstable_declared", issue = "38412")]
+        pub i32,
+        #[unstable(feature = "unstable_undeclared", issue = "38412")]
+        pub i32,
+
+        pub(crate) i32,
+        pub(m) i32,
+        i32);
+
+    impl Record {
+        #[stable(feature = "unit_test", since = "1.0.0")]
+        pub fn new() -> Self { Default::default() }
+    }
+
+    impl Tuple {
+        #[stable(feature = "unit_test", since = "1.0.0")]
+        pub fn new() -> Self { Default::default() }
+    }
+
+
+    #[stable(feature = "unit_test", since = "0.0.0")]
+    pub trait Trait {
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        type Type;
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        fn stable_trait_method(&self) -> Self::Type;
+        #[unstable(feature = "unstable_undeclared", issue = "38412")]
+        fn unstable_undeclared_trait_method(&self) -> Self::Type;
+        #[unstable(feature = "unstable_declared", issue = "38412")]
+        fn unstable_declared_trait_method(&self) -> Self::Type;
+    }
+
+    #[stable(feature = "unit_test", since = "0.0.0")]
+    impl Trait for Record {
+        type Type = i32;
+        fn stable_trait_method(&self) -> i32 { self.d_priv }
+        fn unstable_undeclared_trait_method(&self) -> i32 { self.d_priv }
+        fn unstable_declared_trait_method(&self) -> i32 { self.d_priv }
+    }
+
+    #[stable(feature = "unit_test", since = "0.0.0")]
+    impl Trait for Tuple {
+        type Type = i32;
+        fn stable_trait_method(&self) -> i32 { self.3 }
+        fn unstable_undeclared_trait_method(&self) -> i32 { self.3 }
+        fn unstable_declared_trait_method(&self) -> i32 { self.3 }
+    }
+
+    impl Record {
+        #[unstable(feature = "unstable_undeclared", issue = "38412")]
+        pub fn unstable_undeclared(&self) -> i32 { self.d_priv }
+        #[unstable(feature = "unstable_declared", issue = "38412")]
+        pub fn unstable_declared(&self) -> i32 { self.d_priv }
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        pub fn stable(&self) -> i32 { self.d_priv }
+
+        #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY
+        pub(crate) fn pub_crate(&self) -> i32 { self.d_priv }
+        #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY
+        pub(m) fn pub_mod(&self) -> i32 { self.d_priv }
+        #[stable(feature = "unit_test", since = "0.0.0")] // SILLY
+        fn private(&self) -> i32 { self.d_priv }
+    }
+
+    impl Tuple {
+        #[unstable(feature = "unstable_undeclared", issue = "38412")]
+        pub fn unstable_undeclared(&self) -> i32 { self.0 }
+        #[unstable(feature = "unstable_declared", issue = "38412")]
+        pub fn unstable_declared(&self) -> i32 { self.0 }
+        #[stable(feature = "unit_test", since = "0.0.0")]
+        pub fn stable(&self) -> i32 { self.0 }
+
+        pub(crate) fn pub_crate(&self) -> i32 { self.0 }
+        pub(m) fn pub_mod(&self) -> i32 { self.0 }
+        fn private(&self) -> i32 { self.0 }
+    }
+}
diff --git a/src/test/compile-fail-fulldeps/explore-issue-38412.rs b/src/test/compile-fail-fulldeps/explore-issue-38412.rs
new file mode 100644 (file)
index 0000000..aab9257
--- /dev/null
@@ -0,0 +1,85 @@
+// 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.
+
+// aux-build:pub_and_stability.rs
+
+#![feature(staged_api)]
+#![feature(unused_feature)]
+
+// A big point of this test is that we *declare* `unstable_declared`,
+// but do *not* declare `unstable_undeclared`. This way we can check
+// that the compiler is letting in uses of declared feature-gated
+// stuff but still rejecting uses of undeclared feature-gated stuff.
+#![feature(unstable_declared)]
+
+extern crate pub_and_stability;
+use pub_and_stability::{Record, Trait, Tuple};
+
+fn main() {
+    // Okay
+    let Record { .. } = Record::new();
+    // Okay (for now; see RFC Issue #902)
+    let Tuple(..) = Tuple::new();
+
+    // Okay
+    let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new();
+    // Okay (for now; see RFC Issue #902)
+    let Tuple(_, _, ..) = Tuple::new(); // analogous to above
+
+    let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } =
+        Record::new();
+    //~^^ ERROR use of unstable library feature 'unstable_undeclared'
+
+    let Tuple(_, _, _, ..) = Tuple::new(); // analogous to previous
+    //~^ ERROR use of unstable library feature 'unstable_undeclared'
+
+    let r = Record::new();
+    let t = Tuple::new();
+
+    r.a_stable_pub;
+    r.a_unstable_declared_pub;
+    r.a_unstable_undeclared_pub; //~ ERROR use of unstable library feature
+    r.b_crate;                   //~ ERROR is private
+    r.c_mod;                     //~ ERROR is private
+    r.d_priv;                    //~ ERROR is private
+
+    t.0;
+    t.1;
+    t.2;                         //~ ERROR use of unstable library feature
+    t.3;                         //~ ERROR is private
+    t.4;                         //~ ERROR is private
+    t.5;                         //~ ERROR is private
+
+    r.stable_trait_method();
+    r.unstable_declared_trait_method();
+    r.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature
+
+    r.stable();
+    r.unstable_declared();
+    r.unstable_undeclared();              //~ ERROR use of unstable library feature
+
+    r.pub_crate();                        //~ ERROR `pub_crate` is private
+    r.pub_mod();                          //~ ERROR `pub_mod` is private
+    r.private();                          //~ ERROR `private` is private
+
+    let t = Tuple::new();
+    t.stable_trait_method();
+    t.unstable_declared_trait_method();
+    t.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature
+
+    t.stable();
+    t.unstable_declared();
+    t.unstable_undeclared();              //~ ERROR use of unstable library feature
+
+    t.pub_crate();                        //~ ERROR `pub_crate` is private
+    t.pub_mod();                          //~ ERROR `pub_mod` is private
+    t.private();                          //~ ERROR `private` is private
+
+}
index abf11637631f46b4278e331ee4a2102174319b33..5d5e61270b61dd4e86bb0f1e29138cf44c1b4a4a 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index 8a92ca74f376a027300d5cf72a36fe94acc05854..cd8750bc89c42c8022ab2c50bfe834193540b0a4 100644 (file)
@@ -11,7 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro, proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index 8d26207273d4288bd1b53c8809be4c6127821155..53b2c23e5d7df2d8b4a70d4dc79dc8cb0a0e5928 100644 (file)
@@ -11,8 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index 70b778b1030e7eb21228e345452b8a0a38718f9a..5787546fb1e5a92dbdfea507a352fb9b55e1fd56 100644 (file)
@@ -11,8 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index aae8b63e25354d6a13771911f8b9323bd303d729..841b39eaed07bb6ab04940b671fb55fe91ce7a44 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 // force-host
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index f426fe5437671ccd2e66d023af44cc675f0cf45f..3274f0324e1cbd25b10c52a5e0fb6549687c4e01 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 // force-host
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index d8952e3478b6c3a36b017a91c5df2c96c7c397c1..2d492d341ebbaa2aea3098537fdc9277dee5aa9f 100644 (file)
@@ -11,8 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index 1187b5102e23fa6a29a3d7a52995eb3be85c6e81..a7b5d1e3e54cf94e65eb0ce618a56d226577fd25 100644 (file)
@@ -11,8 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_38586.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_38586.rs
new file mode 100644 (file)
index 0000000..10da846
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro, proc_macro_lib)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+#[proc_macro_derive(A)]
+pub fn derive_a(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    "fn f() { println!(\"{}\", foo); }".parse().unwrap()
+}
index bdb3c09c4d723c9ef64b73feb431135599bd2de7..87b32096d7b01c83f1821edfbb6d45029ae0cd73 100644 (file)
@@ -11,7 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index 4cc6b9f984c949d9825a542824a5f62f972489dc..0e4ac9fe1eaf53c6673ba0205c0c45c1b79a418d 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:derive-bad.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_bad;
 
index eb0bb00be91750817c45515cfba731de58183b10..f36236c53562d2ba085876d97cd949181abce5ff 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-a.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 4f4ed90f8fca2be697a1c707da5218aaa2431ad5..e4fcbb117a5057c0dd55eb757713496102a08bad 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-unstable-2.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 84ac776a765a2631f6505e54340482f7c1bfc620..836e336fc22f013e86983a5c0530a0ebac944719 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-unstable.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 48b73e733318514fc6fc9203b125cfa525164a98..477039bd7a2fa923af73cc77cd17c1605a7d7aae 100644 (file)
@@ -11,7 +11,6 @@
 // error-pattern: cannot export macro_rules! macros from a `proc-macro` crate
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
 
 #[macro_export]
 macro_rules! foo {
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs
deleted file mode 100644 (file)
index f5618fc..0000000
+++ /dev/null
@@ -1,13 +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.
-
-// error-pattern: the `proc-macro` crate type is experimental
-
-#![crate_type = "proc-macro"]
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs
deleted file mode 100644 (file)
index 9c40532..0000000
+++ /dev/null
@@ -1,13 +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.
-
-extern crate proc_macro; //~ ERROR: use of unstable library feature
-
-fn main() {}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs
deleted file mode 100644 (file)
index bb6b575..0000000
+++ /dev/null
@@ -1,15 +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.
-
-#![crate_type = "proc-macro"]
-
-#[proc_macro_derive(Foo)] //~ ERROR: is an experimental feature
-pub fn foo() {
-}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
deleted file mode 100644 (file)
index 6a8fcdf..0000000
+++ /dev/null
@@ -1,17 +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.
-
-// aux-build:derive-a.rs
-
-#[macro_use]
-extern crate derive_a;
-
-#[derive(A)] //~ ERROR custom derive macros are experimentally supported
-struct S;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs
deleted file mode 100644 (file)
index 672579c..0000000
+++ /dev/null
@@ -1,12 +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.
-
-#[cfg(proc_macro)] //~ ERROR: experimental and subject to change
-fn foo() {}
index 70c8db5ddd2ecb0c36c7ca2d0eebe469b03741a2..f37980c5e0f5428d8d0e4404f296aa88b38ef143 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(proc_macro, proc_macro_lib)]
-
 extern crate proc_macro;
 
 #[proc_macro_derive(Foo)]
index 8f907183cc39b2b349d59c6745737b5b317605ba..fae2439344fb08ab6b94b9278a9c1c5f17dca235 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-a.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 6d1030026dba24c2e937bf015a75a43aa5f4d0e7..691c28058012215ee21aabe8ca48cf06e726e769 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:derive-a-b.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_a_b;
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-38586.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-38586.rs
new file mode 100644 (file)
index 0000000..42475e6
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue_38586.rs
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate issue_38586;
+
+#[derive(A)] //~ ERROR `foo`
+struct A;
+
+fn main() {}
index 2a68accf91f714ca5b824bde2e339382f5578632..4133e75e3a62d8f33ca7d1c80a1db23e020b544a 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-b.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 39c27e82fa5b3dd9b538747d181802fa93264442..f9906b650fb878c2b7c4340025b2719c15d9bd6b 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:derive-panic.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_panic;
 
index 651a277d4abd5eab31d98efce63c2ec8282046b2..4ad1cf79d61c6fbf71475fbfa56dc479caf1f41d 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:derive-b.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 2bf25892c44d223e7860d103b4d95811a599866c..238dde5160cd4bd1ad4edb9827d0ba616fd66b6a 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index 1bcd4b15eb86350b20993a49934c1967e26b582f..8c5affb7b5ab3558636ded7a69d44dd6ac1caa75 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index dc828fbf7d160ef960c64cfa1370935cfcdd9beb..d76cf003ed14ded5c26564a95c5cb6ba0ddf8087 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:derive-a.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_a;
 #[macro_use]
index b7df9489dff30f46529df1aeacb8badd0b3dbc56..6d6b5a23e941fbbcbf22d48507e1e6b364331f57 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 #![allow(warnings)]
 
 extern crate proc_macro;
index 906642d8555806c8f71de42d8426f518fc59c100..b72b0d661901fbf0d9b3a8bbc215628067e49919 100644 (file)
@@ -8,11 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(unreachable_patterns)]
+
 fn main() {
     let foo = Some(1);
     match foo {
-        Some(bar) => {/* ... */}
+        Some(_) => {/* ... */}
         None => {/* ... */}
-        _ => {/* ... */} //~ ERROR E0001
+        _ => {/* ... */} //~ ERROR unreachable pattern
     }
 }
diff --git a/src/test/compile-fail/E0204.rs b/src/test/compile-fail/E0204.rs
deleted file mode 100644 (file)
index 0f108a1..0000000
+++ /dev/null
@@ -1,28 +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.
-
-struct Foo {
-    foo: Vec<u32>,
-}
-
-impl Copy for Foo { }
-//~^ ERROR E0204
-//~| NOTE field `foo` does not implement `Copy`
-
-#[derive(Copy)]
-//~^ ERROR E0204
-//~| NOTE field `ty` does not implement `Copy`
-//~| NOTE in this expansion of #[derive(Copy)]
-struct Foo2<'a> {
-    ty: &'a mut bool,
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/E0205.rs b/src/test/compile-fail/E0205.rs
deleted file mode 100644 (file)
index c73e753..0000000
+++ /dev/null
@@ -1,30 +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.
-
-enum Foo {
-    Bar(Vec<u32>),
-    Baz,
-}
-
-impl Copy for Foo { }
-//~^ ERROR the trait `Copy` may not be implemented for this type
-//~| NOTE variant `Bar` does not implement `Copy`
-
-#[derive(Copy)]
-//~^ ERROR the trait `Copy` may not be implemented for this type
-//~| NOTE variant `Bar` does not implement `Copy`
-//~| NOTE in this expansion of #[derive(Copy)]
-enum Foo2<'a> {
-    Bar(&'a mut bool),
-    Baz,
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/const-eval-overflow0.rs b/src/test/compile-fail/const-eval-overflow0.rs
deleted file mode 100644 (file)
index 7db7de9..0000000
+++ /dev/null
@@ -1,100 +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.
-
-#![allow(unused_imports)]
-
-// Note: the relevant lint pass here runs before some of the constant
-// evaluation below (e.g. that performed by trans and llvm), so if you
-// change this warn to a deny, then the compiler will exit before
-// those errors are detected.
-
-use std::fmt;
-use std::{i8, i16, i32, i64, isize};
-use std::{u8, u16, u32, u64, usize};
-
-const VALS_I8: (i8, i8, i8, i8) =
-    (-i8::MIN,
-     i8::MIN - 1,
-     i8::MAX + 1,
-     i8::MIN * 2,
-     );
-
-const VALS_I16: (i16, i16, i16, i16) =
-    (-i16::MIN,
-     i16::MIN - 1,
-     i16::MAX + 1,
-     i16::MIN * 2,
-     );
-
-const VALS_I32: (i32, i32, i32, i32) =
-    (-i32::MIN,
-     i32::MIN - 1,
-     i32::MAX + 1,
-     i32::MIN * 2,
-     );
-
-const VALS_I64: (i64, i64, i64, i64) =
-    (-i64::MIN,
-     i64::MIN - 1,
-     i64::MAX + 1,
-     i64::MAX * 2,
-     );
-
-const VALS_U8: (u8, u8, u8, u8) =
-    (-u8::MIN,
-     //~^ ERROR unary negation of unsigned integer
-     //~| HELP use a cast or the `!` operator
-     u8::MIN - 1,
-     u8::MAX + 1,
-     u8::MAX * 2,
-     );
-
-const VALS_U16: (u16, u16, u16, u16) =
-    (-u16::MIN,
-     //~^ ERROR unary negation of unsigned integer
-     //~| HELP use a cast or the `!` operator
-     u16::MIN - 1,
-     u16::MAX + 1,
-     u16::MAX * 2,
-     );
-
-const VALS_U32: (u32, u32, u32, u32) =
-    (-u32::MIN,
-     //~^ ERROR unary negation of unsigned integer
-     //~| HELP use a cast or the `!` operator
-     u32::MIN - 1,
-     u32::MAX + 1,
-     u32::MAX * 2,
-     );
-
-const VALS_U64: (u64, u64, u64, u64) =
-    (-u64::MIN,
-     //~^ ERROR unary negation of unsigned integer
-     //~| HELP use a cast or the `!` operator
-     u64::MIN - 1,
-     u64::MAX + 1,
-     u64::MAX * 2,
-     );
-
-fn main() {
-    foo(VALS_I8);
-    foo(VALS_I16);
-    foo(VALS_I32);
-    foo(VALS_I64);
-
-    foo(VALS_U8);
-    foo(VALS_U16);
-    foo(VALS_U32);
-    foo(VALS_U64);
-}
-
-fn foo<T:fmt::Debug>(x: T) {
-    println!("{:?}", x);
-}
index 98cc2fc0c3e0cf9ec22d2de7dde2b3c5d5e04163..599e31341f2332a69a6c84c31c804698df838120 100644 (file)
@@ -16,16 +16,13 @@ impl std::ops::Neg for S {
     fn neg(self) -> u32 { 0 }
 }
 
-// FIXME(eddyb) move this back to a `-1` literal when
-// MIR building stops eagerly erroring in that case.
-const _MAX: usize = -(2 - 1);
-//~^ WARN unary negation of unsigned integer
-//~| ERROR unary negation of unsigned integer
-//~| HELP use a cast or the `!` operator
-
 fn main() {
+    let _max: usize = -1;
+    //~^ ERROR cannot apply unary operator `-` to type `usize`
+
     let x = 5u8;
-    let _y = -x; //~ ERROR unary negation of unsigned integer
-    //~^ HELP use a cast or the `!` operator
+    let _y = -x;
+    //~^ ERROR cannot apply unary operator `-` to type `u8`
+
     -S; // should not trigger the gate; issue 26840
 }
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
deleted file mode 100644 (file)
index 89ae1a0..0000000
+++ /dev/null
@@ -1,34 +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.
-
-// Test that negating unsigned integers doesn't compile
-
-struct S;
-impl std::ops::Neg for S {
-    type Output = u32;
-    fn neg(self) -> u32 { 0 }
-}
-
-fn main() {
-    let a = -1;
-    //~^ ERROR E0080
-    //~| unary negation of unsigned integer
-    let _b : u8 = a; // for infering variable a to u8.
-
-    let _d = -1u8;
-    //~^ ERROR E0080
-    //~| unary negation of unsigned integer
-
-    for _ in -10..10u8 {}
-    //~^ ERROR E0080
-    //~| unary negation of unsigned integer
-
-    -S; // should not trigger the gate; issue 26840
-}
index 1978068575b95340900a797d4dfa8176f7543f40..a8d2c55255340ceca1c776cd07723836805d1080 100644 (file)
@@ -10,6 +10,9 @@
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![deny(unreachable_patterns)]
 
 enum IntList {
     Cons(isize, Box<IntList>),
@@ -19,9 +22,8 @@ enum IntList {
 fn tail(source_list: &IntList) -> IntList {
     match source_list {
         &IntList::Cons(val, box ref next_list) => tail(next_list),
-        &IntList::Cons(val, box Nil)           => IntList::Cons(val, box Nil),
+        &IntList::Cons(val, box IntList::Nil)  => IntList::Cons(val, box IntList::Nil),
 //~^ ERROR unreachable pattern
-//~^^ WARN pattern binding `Nil` is named the same as one of the variants of the type `IntList`
         _                          => panic!()
     }
 }
index 978d6f59b2df455b41b91ecc45d7244c2f7f6e88..4df1e24dcfbd53c05d12653f63e47e5a37dd8b45 100644 (file)
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 #![feature(slice_patterns)]
+#![allow(unused_variables)]
+#![deny(unreachable_patterns)]
 
 fn main() {
     let sl = vec![1,2,3];
index 28c2c7bc0e2e7946b735ee3146fea72f711a1c1a..2e815548e89134c7e95e16cc1fe318f0c0fc8df0 100644 (file)
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(overflowing_literals)]
+#![deny(unreachable_patterns)]
+
 fn test(val: u8) {
   match val {
     256 => print!("0b1110\n"),
index e79be99a346fa8692251b9c0508ba47bee897653..d11fe99c07f6b738433a029d386904bd2e2fa83b 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(unreachable_patterns)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+
 pub enum E {
     A,
     B,
diff --git a/src/test/compile-fail/issue-27942.rs b/src/test/compile-fail/issue-27942.rs
new file mode 100644 (file)
index 0000000..b855279
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+pub trait Resources<'a> {}
+
+pub trait Buffer<'a, R: Resources<'a>> {
+    fn select(&self) -> BufferViewHandle<R>;
+    //~^ ERROR mismatched types
+    //~| lifetime mismatch
+    //~| NOTE expected type `Resources<'_>`
+    //~| NOTE    found type `Resources<'a>`
+    //~| NOTE the lifetime 'a as defined on the method body at 14:4...
+    //~| NOTE ...does not necessarily outlive the anonymous lifetime #1 defined on the method body
+    //~| ERROR mismatched types
+    //~| lifetime mismatch
+    //~| NOTE expected type `Resources<'_>`
+    //~| NOTE    found type `Resources<'a>`
+    //~| NOTE the anonymous lifetime #1 defined on the method body at 14:4...
+    //~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the method body
+}
+
+pub struct BufferViewHandle<'a, R: 'a+Resources<'a>>(&'a R);
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-30240-b.rs b/src/test/compile-fail/issue-30240-b.rs
new file mode 100644 (file)
index 0000000..cf6935b
--- /dev/null
@@ -0,0 +1,26 @@
+// 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(unreachable_patterns)]
+
+fn main() {
+    match "world" {
+        "hello" => {}
+        _ => {},
+    }
+
+    match "world" {
+        ref _x if false => {}
+        "hello" => {}
+        "hello" => {} //~ ERROR unreachable pattern
+        _ => {},
+    }
+}
+
index 9b105e7ec159d193ff8997e4850398234c8563a0..60fb307d4e1a4a141689f3f7d4e7258cd6eed5c8 100644 (file)
@@ -16,6 +16,5 @@ fn main() {
     match "world" { //~ ERROR non-exhaustive patterns: `&_`
         ref _x if false => {}
         "hello" => {}
-        "hello" => {} //~ ERROR unreachable pattern
     }
 }
index 26508a47224253462be8ff723601771a5af4383f..01150ff13740f1446a06b8922507e0578c0af552 100644 (file)
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+#![deny(unreachable_patterns)]
+
 enum Stack<T> {
     Nil,
     Cons(T, Box<Stack<T>>)
index 4997a6fee195b4c736816bd9c6d3bc150ac8c425..e2b80215caf61894fec84d8235657379ae02f297 100644 (file)
@@ -8,6 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+#![deny(unreachable_patterns)]
+//~^ NOTE lint level defined here
+//~^^ NOTE lint level defined here
+//~^^^ NOTE lint level defined here
+
+#[derive(Clone, Copy)]
 enum Enum {
     Var1,
     Var2,
@@ -41,13 +50,4 @@ fn main() {
         //~^ ERROR unreachable pattern
         //~^^ NOTE this is an unreachable pattern
     };
-    // `_` need not emit a note, it is pretty obvious already.
-    let t = (Var1, Var1);
-    match t {
-        (Var1, b) => (),
-        _ => (),
-        anything => ()
-        //~^ ERROR unreachable pattern
-        //~^^ NOTE this is an unreachable pattern
-    };
 }
index b25e683db09065f94ddf961c9dd9396414f0138f..cc69a76e04331e411c12a9a217946993ae5c7479 100644 (file)
@@ -40,6 +40,5 @@ fn main() {
         box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
         },
-        _ => panic!("WAT") //~ ERROR unreachable pattern
     };
 }
diff --git a/src/test/compile-fail/issue-37884.rs b/src/test/compile-fail/issue-37884.rs
new file mode 100644 (file)
index 0000000..a73b1db
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+struct RepeatMut<'a, T>(T, &'a ());
+
+impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
+    type Item = &'a mut T;
+    fn next(&'a mut self) -> Option<Self::Item>
+    //~^ ERROR method not compatible with trait
+    //~| lifetime mismatch
+    //~| NOTE expected type `fn(&mut RepeatMut<'a, T>) -> std::option::Option<&mut T>`
+    //~| NOTE    found type `fn(&'a mut RepeatMut<'a, T>) -> std::option::Option<&mut T>`
+    {
+    //~^ NOTE the anonymous lifetime #1 defined on the body
+    //~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the body
+        Some(&mut self.0)
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs
new file mode 100644 (file)
index 0000000..00305eb
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+fn main() {
+    let Box(a) = loop { };
+    //~^ ERROR field `0` of struct `std::boxed::Box` is private
+
+    // (The below is a trick to allow compiler to infer a type for
+    // variable `a` without attempting to ascribe a type to the
+    // pattern or otherwise attempting to name the Box type, which
+    // would run afoul of issue #22207)
+    let _b: *mut i32 = *a;
+}
index af9b21dadd1d083b08d9126053109004c78cab46..57c2166565f96d7d7622a5932105047c217a5404 100644 (file)
@@ -21,8 +21,9 @@ fn main() {
 
     let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345
 
-    macro_rules! m {
-        () => { $crate::foo::bar(); }
-    }
-    m!(); // issue #37357
+    macro_rules! m { () => {
+        $crate::foo::bar(); // issue #37357
+        ::foo::bar(); // issue #38682
+    } }
+    m!();
 }
diff --git a/src/test/compile-fail/match-argm-statics-2.rs b/src/test/compile-fail/match-argm-statics-2.rs
new file mode 100644 (file)
index 0000000..40dcf3d
--- /dev/null
@@ -0,0 +1,71 @@
+// 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.
+
+use self::Direction::{North, East, South, West};
+
+struct NewBool(bool);
+
+enum Direction {
+    North,
+    East,
+    South,
+    West
+}
+
+const TRUE_TRUE: (bool, bool) = (true, true);
+
+fn nonexhaustive_1() {
+    match (true, false) {
+    //~^ ERROR non-exhaustive patterns: `(true, false)` not covered
+        TRUE_TRUE => (),
+        (false, false) => (),
+        (false, true) => ()
+    }
+}
+
+const NONE: Option<Direction> = None;
+const EAST: Direction = East;
+
+fn nonexhaustive_2() {
+    match Some(Some(North)) {
+    //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
+        Some(NONE) => (),
+        Some(Some(North)) => (),
+        Some(Some(EAST)) => (),
+        Some(Some(South)) => (),
+        None => ()
+    }
+}
+
+const NEW_FALSE: NewBool = NewBool(false);
+struct Foo {
+    bar: Option<Direction>,
+    baz: NewBool
+}
+
+const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
+
+fn nonexhaustive_3() {
+    match (Foo { bar: Some(North), baz: NewBool(true) }) {
+    //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
+        Foo { bar: None, baz: NewBool(true) } => (),
+        Foo { bar: _, baz: NEW_FALSE } => (),
+        Foo { bar: Some(West), baz: NewBool(true) } => (),
+        Foo { bar: Some(South), .. } => (),
+        Foo { bar: Some(EAST), .. } => ()
+    }
+}
+
+fn main() {
+    nonexhaustive_1();
+    nonexhaustive_2();
+    nonexhaustive_3();
+}
+
index 9b313f248fcbb22b9dd48e4c66f805e62be8ea60..40d73ab51c76228ca9f45ed6b38ad420f003a454 100644 (file)
@@ -7,10 +7,16 @@
 // <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)]
+#![deny(unreachable_patterns)]
+
 use self::Direction::{North, East, South, West};
 
+#[derive(PartialEq, Eq)]
 struct NewBool(bool);
 
+#[derive(PartialEq, Eq)]
 enum Direction {
     North,
     East,
@@ -20,15 +26,6 @@ enum Direction {
 
 const TRUE_TRUE: (bool, bool) = (true, true);
 
-fn nonexhaustive_1() {
-    match (true, false) {
-    //~^ ERROR non-exhaustive patterns: `(true, false)` not covered
-        TRUE_TRUE => (),
-        (false, false) => (),
-        (false, true) => ()
-    }
-}
-
 fn unreachable_1() {
     match (true, false) {
         TRUE_TRUE => (),
@@ -43,17 +40,6 @@ fn unreachable_1() {
 const NONE: Option<Direction> = None;
 const EAST: Direction = East;
 
-fn nonexhaustive_2() {
-    match Some(Some(North)) {
-    //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
-        Some(NONE) => (),
-        Some(Some(North)) => (),
-        Some(Some(EAST)) => (),
-        Some(Some(South)) => (),
-        None => ()
-    }
-}
-
 fn unreachable_2() {
     match Some(Some(North)) {
         Some(NONE) => (),
@@ -73,19 +59,6 @@ struct Foo {
     baz: NewBool
 }
 
-const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
-
-fn nonexhaustive_3() {
-    match (Foo { bar: Some(North), baz: NewBool(true) }) {
-    //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
-        Foo { bar: None, baz: NewBool(true) } => (),
-        Foo { bar: _, baz: NEW_FALSE } => (),
-        Foo { bar: Some(West), baz: NewBool(true) } => (),
-        Foo { bar: Some(South), .. } => (),
-        Foo { bar: Some(EAST), .. } => ()
-    }
-}
-
 fn unreachable_3() {
     match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
         Foo { bar: None, baz: NewBool(true) } => (),
@@ -100,9 +73,6 @@ fn unreachable_3() {
 }
 
 fn main() {
-    nonexhaustive_1();
-    nonexhaustive_2();
-    nonexhaustive_3();
     unreachable_1();
     unreachable_2();
     unreachable_3();
diff --git a/src/test/compile-fail/match-byte-array-patterns-2.rs b/src/test/compile-fail/match-byte-array-patterns-2.rs
new file mode 100644 (file)
index 0000000..ad7e931
--- /dev/null
@@ -0,0 +1,26 @@
+// 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(advanced_slice_patterns, slice_patterns)]
+
+fn main() {
+    let buf = &[0, 1, 2, 3];
+
+    match buf { //~ ERROR non-exhaustive
+        b"AAAA" => {}
+    }
+
+    let buf: &[u8] = buf;
+
+    match buf { //~ ERROR non-exhaustive
+        b"AAAA" => {}
+    }
+}
+
index 86323656b873e0db44604c1d95bf5556b3be60fc..1ff07eae1c9c03a654d9cef0f63d7718df1ea873 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(advanced_slice_patterns, slice_patterns)]
+#![deny(unreachable_patterns)]
 
 fn main() {
     let buf = &[0, 1, 2, 3];
@@ -37,10 +38,6 @@ fn main() {
         _ => {}
     }
 
-    match buf { //~ ERROR non-exhaustive
-        b"AAAA" => {}
-    }
-
     let buf: &[u8] = buf;
 
     match buf {
@@ -66,8 +63,4 @@ fn main() {
         b"AAAA" => {}, //~ ERROR unreachable pattern
         _ => {}
     }
-
-    match buf { //~ ERROR non-exhaustive
-        b"AAAA" => {}
-    }
 }
index 825a485d529565b451ababfd61e0322dd76a1308..256aa180f4a59e84d1f3b03973ac4fd36468a27e 100644 (file)
@@ -14,6 +14,8 @@
 //error-pattern: unreachable
 //error-pattern: unreachable
 
+#![deny(unreachable_patterns)]
+
 fn main() {
     match 5 {
       1 ... 10 => { }
index 042ec95f7e753787500869760c5faa44b016f980..1cdbba17f658ad9501169068232e68ce3774af1a 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(slice_patterns)]
+#![deny(unreachable_patterns)]
 
 // The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose
 // arity is always 0, an ICE occurs.
@@ -19,7 +20,7 @@ fn main() {
     let homura = [1, 2, 3];
 
     match homura {
-        [1, ref madoka, 3] => (),
+        [1, ref _madoka, 3] => (),
         [1, 2, 3] => (), //~ ERROR unreachable pattern
         [_, _, _] => (),
     }
index c0fc75f9713a878e8c80c9cd883098b8836c4ac2..fd4bd1c7b944b7b879e3160f3e1a89cf65cc0dd4 100644 (file)
@@ -12,7 +12,7 @@
 
 fn check(list: &[Option<()>]) {
     match list {
-    //~^ ERROR `&[None, Some(_), None, _]` and `&[Some(_), Some(_), None, _]` not covered
+    //~^ ERROR `&[_, Some(_), None, _]` not covered
         &[] => {},
         &[_] => {},
         &[_, _] => {},
index 60d0c24bb3d3679002d03d3d4d5ffe9b590f56c7..dd9379c756d12a147d56d9a71c5e1308cb516d91 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(slice_patterns)]
+#![deny(unreachable_patterns)]
 
 fn a() {
     let v = [1, 2, 3];
index 4d9b3aea1124bbb2c84c22408c7c7e1d6d20d80a..472b054b08777c19df99f71d58823864232199c9 100644 (file)
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 #![feature(slice_patterns)]
+#![deny(unreachable_patterns)]
+#![allow(unused_variables)]
 
 fn main() {
     let x: Vec<(isize, isize)> = Vec::new();
@@ -24,7 +26,7 @@ fn main() {
                               "baz".to_string()];
     let x: &[String] = &x;
     match *x {
-        [a, _, _, ..] => { println!("{}", a); }
+        [ref a, _, _, ..] => { println!("{}", a); }
         [_, _, _, _, _] => { } //~ ERROR unreachable pattern
         _ => { }
     }
index 9f7ebc261ad2e64251e3494c275ba9b3c09654f8..dda30141b4a06e9f79b9ee5d46f22587d59683b3 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(unreachable_patterns)]
+
 struct Foo {
     x: isize,
     y: isize,
@@ -16,7 +18,7 @@ struct Foo {
 pub fn main() {
     let a = Foo { x: 1, y: 2 };
     match a {
-        Foo { x: x, y: y } => (),
+        Foo { x: _x, y: _y } => (),
         Foo { .. } => () //~ ERROR unreachable pattern
     }
 
diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs
new file mode 100644 (file)
index 0000000..4755fdd
--- /dev/null
@@ -0,0 +1,38 @@
+// 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.
+
+#![feature(never_type)]
+
+mod foo {
+    pub struct SecretlyEmpty {
+        _priv: !,
+    }
+
+    pub struct NotSoSecretlyEmpty {
+        pub _pub: !,
+    }
+}
+
+struct NotSoSecretlyEmpty {
+    _priv: !,
+}
+
+enum Foo {
+    A(foo::SecretlyEmpty),
+    B(foo::NotSoSecretlyEmpty),
+    C(NotSoSecretlyEmpty),
+    D(u32),
+}
+
+fn main() {
+    let x: Foo = Foo::D(123);
+    let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
+}
+
diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs
new file mode 100644 (file)
index 0000000..0de29f3
--- /dev/null
@@ -0,0 +1,49 @@
+// 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.
+
+#![feature(box_patterns)]
+#![feature(slice_patterns)]
+#![feature(box_syntax)]
+#![feature(never_type)]
+#![deny(unreachable_patterns)]
+
+mod foo {
+    pub struct SecretlyEmpty {
+        _priv: !,
+    }
+}
+
+struct NotSoSecretlyEmpty {
+    _priv: !,
+}
+
+fn main() {
+    let x: &[!] = &[];
+
+    match x {
+        &[]   => (),
+        &[..] => (),    //~ ERROR unreachable pattern
+    };
+
+    let x: Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]> = Err(&[]);
+    match x {
+        Ok(box _) => (),    //~ ERROR unreachable pattern
+        Err(&[]) => (),
+        Err(&[..]) => (),   //~ ERROR unreachable pattern
+    }
+
+    let x: Result<foo::SecretlyEmpty, Result<NotSoSecretlyEmpty, u32>> = Err(Err(123));
+    match x {
+        Ok(_y) => (),
+        Err(Err(_y)) => (),
+        Err(Ok(_y)) => (),  //~ ERROR unreachable pattern
+    }
+}
+
index bc93b86a391191229ae64e45f89aaf94eb469799..df827d2c78421f31b34203317d053ab0321006fc 100644 (file)
@@ -8,11 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:unreachable pattern
-
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![allow(dead_code)]
+#![deny(unreachable_patterns)]
+
+enum Foo { A(Box<Foo>, isize), B(usize), }
 
-enum foo { a(Box<foo>, isize), b(usize), }
+fn main() {
+    match Foo::B(1) {
+        Foo::B(_) | Foo::A(box _, 1) => { }
+        Foo::A(_, 1) => { } //~ ERROR unreachable pattern
+        _ => { }
+    }
+}
 
-fn main() { match foo::b(1) { foo::b(_) | foo::a(box _, 1) => { } foo::a(_, 1) => { } } }
diff --git a/src/test/debuginfo/issue-12886.rs b/src/test/debuginfo/issue-12886.rs
new file mode 100644 (file)
index 0000000..c30ee92
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2013-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.
+
+// ignore-windows failing on 64-bit bots FIXME #17638
+// ignore-lldb
+// ignore-aarch64
+
+// compile-flags:-g
+
+// gdb-command:run
+// gdb-command:next
+// gdb-check:[...]35[...]s
+// gdb-command:continue
+
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+// IF YOU MODIFY THIS FILE, BE CAREFUL TO ADAPT THE LINE NUMBERS IN THE DEBUGGER COMMANDS
+
+// This test makes sure that gdb does not set unwanted breakpoints in inlined functions. If a
+// breakpoint existed in unwrap(), then calling `next` would (when stopped at `let s = ...`) stop
+// in unwrap() instead of stepping over the function invocation. By making sure that `s` is
+// contained in the output, after calling `next` just once, we can be sure that we did not stop in
+// unwrap(). (The testing framework doesn't allow for checking that some text is *not* contained in
+// the output, which is why we have to make the test in this kind of roundabout way)
+fn bar() -> isize {
+    let s = Some(5).unwrap(); // #break
+    s
+}
+
+fn main() {
+    let _ = bar();
+}
diff --git a/src/test/debuginfo/issue-13213.rs b/src/test/debuginfo/issue-13213.rs
new file mode 100644 (file)
index 0000000..67975d0
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2013-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.
+
+// min-lldb-version: 310
+
+// aux-build:issue13213aux.rs
+
+extern crate issue13213aux;
+
+// compile-flags:-g
+
+// This tests make sure that we get no linker error when using a completely inlined static. Some
+// statics that are marked with AvailableExternallyLinkage in the importing crate, may actually not
+// be available because they have been optimized out from the exporting crate.
+fn main() {
+    let b: issue13213aux::S = issue13213aux::A;
+    println!("Nothing to do here...");
+}
diff --git a/src/test/debuginfo/issue-14411.rs b/src/test/debuginfo/issue-14411.rs
new file mode 100644 (file)
index 0000000..d334e33
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2013-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.
+
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// No debugger interaction required: just make sure it compiles without
+// crashing.
+
+fn test(a: &Vec<u8>) {
+  print!("{}", a.len());
+}
+
+pub fn main() {
+  let data = vec![];
+  test(&data);
+}
diff --git a/src/test/debuginfo/issue-22656.rs b/src/test/debuginfo/issue-22656.rs
new file mode 100644 (file)
index 0000000..a971e06
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2013-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.
+
+
+// This test makes sure that the LLDB pretty printer does not throw an exception
+// when trying to handle a Vec<> or anything else that contains zero-sized
+// fields.
+
+// min-lldb-version: 310
+// ignore-gdb
+// ignore-tidy-linelength
+
+// compile-flags:-g
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+
+// lldb-command:print v
+// lldb-check:[...]$0 = vec![1, 2, 3]
+// lldb-command:print zs
+// lldb-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
+// lldb-command:continue
+
+#![allow(unused_variables)]
+#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+struct ZeroSizedStruct;
+
+struct StructWithZeroSizedField {
+    x: ZeroSizedStruct,
+    y: u32,
+    z: ZeroSizedStruct,
+    w: u64
+}
+
+fn main() {
+    let v = vec![1,2,3];
+
+    let zs = StructWithZeroSizedField {
+        x: ZeroSizedStruct,
+        y: 123,
+        z: ZeroSizedStruct,
+        w: 456
+    };
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
diff --git a/src/test/debuginfo/issue-7712.rs b/src/test/debuginfo/issue-7712.rs
new file mode 100644 (file)
index 0000000..124cdfb
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2013 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:-C debuginfo=1
+// min-lldb-version: 310
+
+pub trait TraitWithDefaultMethod : Sized {
+    fn method(self) {
+        ()
+    }
+}
+
+struct MyStruct;
+
+impl TraitWithDefaultMethod for MyStruct { }
+
+pub fn main() {
+    MyStruct.method();
+}
diff --git a/src/test/debuginfo/issue12886.rs b/src/test/debuginfo/issue12886.rs
deleted file mode 100644 (file)
index c30ee92..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013-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.
-
-// ignore-windows failing on 64-bit bots FIXME #17638
-// ignore-lldb
-// ignore-aarch64
-
-// compile-flags:-g
-
-// gdb-command:run
-// gdb-command:next
-// gdb-check:[...]35[...]s
-// gdb-command:continue
-
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// IF YOU MODIFY THIS FILE, BE CAREFUL TO ADAPT THE LINE NUMBERS IN THE DEBUGGER COMMANDS
-
-// This test makes sure that gdb does not set unwanted breakpoints in inlined functions. If a
-// breakpoint existed in unwrap(), then calling `next` would (when stopped at `let s = ...`) stop
-// in unwrap() instead of stepping over the function invocation. By making sure that `s` is
-// contained in the output, after calling `next` just once, we can be sure that we did not stop in
-// unwrap(). (The testing framework doesn't allow for checking that some text is *not* contained in
-// the output, which is why we have to make the test in this kind of roundabout way)
-fn bar() -> isize {
-    let s = Some(5).unwrap(); // #break
-    s
-}
-
-fn main() {
-    let _ = bar();
-}
diff --git a/src/test/debuginfo/issue13213.rs b/src/test/debuginfo/issue13213.rs
deleted file mode 100644 (file)
index 67975d0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013-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.
-
-// min-lldb-version: 310
-
-// aux-build:issue13213aux.rs
-
-extern crate issue13213aux;
-
-// compile-flags:-g
-
-// This tests make sure that we get no linker error when using a completely inlined static. Some
-// statics that are marked with AvailableExternallyLinkage in the importing crate, may actually not
-// be available because they have been optimized out from the exporting crate.
-fn main() {
-    let b: issue13213aux::S = issue13213aux::A;
-    println!("Nothing to do here...");
-}
diff --git a/src/test/debuginfo/issue14411.rs b/src/test/debuginfo/issue14411.rs
deleted file mode 100644 (file)
index d334e33..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013-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.
-
-// min-lldb-version: 310
-
-// compile-flags:-g
-
-// No debugger interaction required: just make sure it compiles without
-// crashing.
-
-fn test(a: &Vec<u8>) {
-  print!("{}", a.len());
-}
-
-pub fn main() {
-  let data = vec![];
-  test(&data);
-}
diff --git a/src/test/debuginfo/issue22656.rs b/src/test/debuginfo/issue22656.rs
deleted file mode 100644 (file)
index a971e06..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013-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.
-
-
-// This test makes sure that the LLDB pretty printer does not throw an exception
-// when trying to handle a Vec<> or anything else that contains zero-sized
-// fields.
-
-// min-lldb-version: 310
-// ignore-gdb
-// ignore-tidy-linelength
-
-// compile-flags:-g
-
-// === LLDB TESTS ==================================================================================
-// lldb-command:run
-
-// lldb-command:print v
-// lldb-check:[...]$0 = vec![1, 2, 3]
-// lldb-command:print zs
-// lldb-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
-// lldb-command:continue
-
-#![allow(unused_variables)]
-#![allow(dead_code)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-struct ZeroSizedStruct;
-
-struct StructWithZeroSizedField {
-    x: ZeroSizedStruct,
-    y: u32,
-    z: ZeroSizedStruct,
-    w: u64
-}
-
-fn main() {
-    let v = vec![1,2,3];
-
-    let zs = StructWithZeroSizedField {
-        x: ZeroSizedStruct,
-        y: 123,
-        z: ZeroSizedStruct,
-        w: 456
-    };
-
-    zzz(); // #break
-}
-
-fn zzz() { () }
diff --git a/src/test/debuginfo/issue7712.rs b/src/test/debuginfo/issue7712.rs
deleted file mode 100644 (file)
index 124cdfb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 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:-C debuginfo=1
-// min-lldb-version: 310
-
-pub trait TraitWithDefaultMethod : Sized {
-    fn method(self) {
-        ()
-    }
-}
-
-struct MyStruct;
-
-impl TraitWithDefaultMethod for MyStruct { }
-
-pub fn main() {
-    MyStruct.method();
-}
index ada9e0b30ccae1cc61010da8c3b819e4211e6dfe..5d3fbd62023871b873767fde4018f59144b0adb7 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 // min-lldb-version: 310
-// ignore-macos FIXME(#37479)
 
 // compile-flags:-g
 
@@ -27,9 +26,9 @@
 
 // lldb-command:run
 // lldb-command:print u
-// lldb-check:[...]$0 = { a = ('\x02', '\x02') b = 514 }
+// lldb-check:[...]$0 = U { a: ('\x02', '\x02'), b: 514 }
 // lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = 257
+// lldb-check:[...]$1 = U { a: ('\x01', '\x01'), b: 257 }
 
 #![allow(unused)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/unsized.rs b/src/test/debuginfo/unsized.rs
new file mode 100644 (file)
index 0000000..b0ce335
--- /dev/null
@@ -0,0 +1,45 @@
+// 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:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+
+// gdb-command:print *a
+// gdbg-check:$1 = {value = [...] "abc"}
+// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]}
+
+// gdb-command:print *b
+// gdbg-check:$2 = {value = {value = [...] "abc"}}
+// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}}
+
+
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+struct Foo<T: ?Sized> {
+    value: T
+}
+
+fn main() {
+    let foo: Foo<Foo<[u8; 4]>> = Foo {
+        value: Foo {
+            value: *b"abc\0"
+        }
+    };
+    let a: &Foo<[u8]> = &foo.value;
+    let b: &Foo<Foo<[u8]>> = &foo;
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
index 3dff45388c75bf212d29ad9ce1600e8205024b30..052317438c2f7a9de60f88d70abae86562479ac3 100644 (file)
@@ -8,6 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(proc_macro)]
 #![allow(unused)]
 #![crate_type = "proc-macro"]
index 3dff45388c75bf212d29ad9ce1600e8205024b30..052317438c2f7a9de60f88d70abae86562479ac3 100644 (file)
@@ -8,6 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(proc_macro)]
 #![allow(unused)]
 #![crate_type = "proc-macro"]
index c291ffbf4e856ffe4285e2407f8f883662b412ca..6fb315731de1706cf7523165c548cfe8593d9c25 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index a2db98049d28705e9209bb14cbdfbf7080fea5ec..03330c3d1700d4b49eb99ba7ab852d609a203eaa 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate foo;
 
index bd9e9158c505229a462d2527e64f9fe495b8859b..2f2524f6ef11513d17e87479214020a6f4875a39 100644 (file)
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index fc9b65c47a9fe56e6fab734bad209228136d5a19..aad8b1b3fbbafcf7a081bfbf3ea7c066dfe73621 100644 (file)
@@ -1,7 +1,7 @@
 -include ../tools.mk
 
 all:
-       # check that #[ignore(cfg(...))] does the right thing.
+       # check that #[cfg_attr(..., ignore)] does the right thing.
        $(RUSTC) --test test-ignore-cfg.rs --cfg ignorecfg
        $(call RUN,test-ignore-cfg) | grep 'shouldnotignore ... ok'
        $(call RUN,test-ignore-cfg) | grep 'shouldignore ... ignored'
index e82282f3d8c583c03d33673d2638470f8e20f44d..7ea7ceafc28766d6a12f0263aa324c950ff8da9e 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:add-impl.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate add_impl;
 
index f062111df9daf486c1863067c9c0a908f7c46ca9..591f3331d28c00382f421852d34df791cf43c583 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:append-impl.rs
 
-#![feature(proc_macro)]
 #![allow(warnings)]
 
 #[macro_use]
index 1d34049db249fa74ef531728ef38a0712bfbf604..3959eccd81e355ebaa1ba4974f1c26572490f471 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index 7260bc4a5e7bb275b72059598f2c2ba56f56f954..fdce709e5bad68e39a2d6e85a6ed2edd67f5aaa5 100644 (file)
@@ -11,8 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index eaada5542274c148ac528e51b6ab56ca7c75dcd2..a253c6224aa685d89cc23cffea8339e1f2e99c06 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index a942adc4c80203d163136ec6f477e6bf8336b8e1..713fb7d10f2fda3293fc00923d22e3b4f4243dc1 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index a02b798c8023e3b21bd58b2d15861664c693d685..c18cda895325b215a2d92a011f0115ec8e991fe8 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index 50f1a390b2939fcf566cc10784d78b095e3104d3..19caafd17b5f3471af563e956a109e6d211ed92e 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index a9257cb4c8b789f9c08119172be6baffe4a6f75c..cfe428bf5f32349474c783659f7b3c1954ccfc95 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index 05a6cbec69c5a2b2c5d385f354d56c907532ae3b..fae2d27ab6b75d821974a741df65f5b7c007ccd1 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-test
 
-#![feature(macro_reexport, proc_macro)]
+#![feature(macro_reexport)]
 
 #[macro_reexport(A)]
 extern crate derive_a;
index bc8a0d575913b083a695b0a13fe4d11263c8dcd0..a2c25ae50e8ec6a1fbdf0ff1ae7145310d27d628 100644 (file)
@@ -11,9 +11,6 @@
 // no-prefer-dynamic
 // compile-flags:--crate-type proc-macro
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
-
 extern crate proc_macro;
 
 use proc_macro::TokenStream;
index 969ed91f595e6d1697fc4e4ff2b80039f8b7512d..f4404b737f952b0dae5e476450c4a49708ca8bb4 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 
 extern crate proc_macro;
 
index 50eaf035962f13acdf8090a0fc1e7e250afb1401..e6831b6bfdf65d41fe52dee5292e8b67ad0da1c4 100644 (file)
@@ -11,8 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![deny(warnings)]
 
 extern crate proc_macro;
index d19b49ab18c075ecd07e0314f85d33e240c06b71..ba1417ecb56e408cf96d2db98c384b32fa4c96f2 100644 (file)
@@ -10,7 +10,6 @@
 
 // aux-build:double.rs
 
-#![feature(proc_macro)]
 #![allow(unused)]
 
 #[macro_use]
index f5bb93f012490d32f75fdb55dc68fcca8cf46b54..f1e1626ddf8ca4340fd1eb292456a47c6196ad85 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:derive-b.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_b;
 
index 608f86bca576899a7ce06a11419baecb4c67869c..ce3ba60b0ecf4b264b17523a8c209cf675416f86 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:derive-same-struct.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_same_struct;
 
index 2f44515a873de52648674e36d6b5d78bbd1270af..a07e8b6cd7e64879d2cd6613f3bfddd4bf38528f 100644 (file)
@@ -12,8 +12,6 @@
 // compile-flags: --test
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index 16f3535adae3bcde9551fac123c8e5ee38386a35..4ccd4615fb6092b7b33b67cc241f86102d59cd54 100644 (file)
@@ -11,7 +11,6 @@
 // aux-build:expand-with-a-macro.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
 #![deny(warnings)]
 
 #[macro_use]
index 431c8c5902749f69476e340c74b3f7b1b2db0689..d15a83a2cbe432afc4fb8a17261e10ce24876fac 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:derive-atob.rs
 // aux-build:derive-ctod.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_atob;
 #[macro_use]
index cd7edb726447bc909a8ef5cadc04e275fdd09a2f..54d651df1f9afacc68e87a89dea3b2cb3af1fe7e 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:derive-a.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_a;
 
index 818308b05a44e7170bf5ace803b6cd3b29cfd8af..c9056e08d4426faba5d9c2fffdcced41ebe4ed6e 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:derive-nothing.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_nothing;
 
index 7f09d8faebbb5a07b878498d648f151cc94abc29..f0a1bfe652857989c9b5dfacf4a74b79f08ea12b 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:derive-a.rs
 // aux-build:derive-reexport.rs
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate derive_reexport;
 
diff --git a/src/test/run-pass/auxiliary/issue_38715.rs b/src/test/run-pass/auxiliary/issue_38715.rs
new file mode 100644 (file)
index 0000000..cad3996
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+#[macro_export]
+macro_rules! foo { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo { () => {} }
diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs
new file mode 100644 (file)
index 0000000..23705d3
--- /dev/null
@@ -0,0 +1,60 @@
+// 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.
+
+#![feature(never_type)]
+#![feature(slice_patterns)]
+#![allow(unreachable_patterns)]
+#![allow(unreachable_code)]
+
+#[allow(dead_code)]
+fn foo(z: !) {
+    let x: Result<!, !> = Ok(z);
+
+    let Ok(_y) = x;
+    let Err(_y) = x;
+
+    let x = [z; 1];
+
+    match x {};
+    match x {
+        [q] => q,
+    };
+}
+
+fn bar(nevers: &[!]) {
+    match nevers {
+        &[]  => (),
+    };
+
+    match nevers {
+        &[]  => (),
+        &[_]  => (),
+        &[_, _, _, ..]  => (),
+    };
+}
+
+fn main() {
+    let x: Result<u32, !> = Ok(123);
+    let Ok(y) = x;
+
+    assert_eq!(123, y);
+
+    match x {
+        Ok(y) => y,
+    };
+
+    match x {
+        Ok(y) => y,
+        Err(e) => match e {},
+    };
+
+    bar(&[]);
+}
+
diff --git a/src/test/run-pass/i128-ffi.rs b/src/test/run-pass/i128-ffi.rs
new file mode 100644 (file)
index 0000000..3b5f488
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+// ignore-stage0
+// ignore-stage1
+
+// MSVC doesn't support 128 bit integers, and other Windows
+// C compilers have very inconsistent views on how the ABI
+// should look like.
+
+// ignore-windows
+
+// Ignore 32 bit targets:
+// ignore-x86, ignore-arm
+
+#![feature(i128_type)]
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    fn identity(f: u128) -> u128;
+    fn square(f: i128) -> i128;
+    fn sub(f: i128, f: i128) -> i128;
+}
+
+fn main() {
+    unsafe {
+        let a = 0x734C_C2F2_A521;
+        let b = 0x33EE_0E2A_54E2_59DA_A0E7_8E41;
+        let b_out = identity(b);
+        assert_eq!(b, b_out);
+        let a_square = square(a);
+        assert_eq!(b, a_square as u128);
+        let k = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210;
+        let k_d = 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420;
+        let k_out = sub(k_d, k);
+        assert_eq!(k, k_out);
+    }
+}
index b7aeb21229ccb6f33528473140368d0c8b4afc8e..a4ff36d20e4fa9c48388e36a0adef338e6c918ed 100644 (file)
@@ -96,4 +96,12 @@ fn main() {
     assert_eq!((-z).checked_mul(-z), Some(0x734C_C2F2_A521));
     assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521));
     assert_eq!((k).checked_mul(k), None);
+    let l: i128 = b(i128::min_value());
+    let o: i128 = b(17);
+    assert_eq!(l.checked_sub(b(2)), None);
+    assert_eq!(l.checked_add(l), None);
+    assert_eq!((-(l + 1)).checked_add(2), None);
+    assert_eq!(l.checked_sub(l), Some(0));
+    assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127));
+    assert_eq!(o.checked_shl(b(128)), None);
 }
diff --git a/src/test/run-pass/issue-18173.rs b/src/test/run-pass/issue-18173.rs
new file mode 100644 (file)
index 0000000..f4266fa
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+trait Foo {
+    type T;
+}
+
+// should be able to use a trait with an associated type without specifying it as an argument
+trait Bar<F: Foo> {
+    fn bar(foo: &F);
+}
+
+pub fn main() {
+}
diff --git a/src/test/run-pass/issue-22008.rs b/src/test/run-pass/issue-22008.rs
new file mode 100644 (file)
index 0000000..3e14512
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+pub fn main() {
+    let command = "a";
+
+    match command {
+        "foo" => println!("foo"),
+        _     => println!("{}", command),
+    }
+}
diff --git a/src/test/run-pass/issue-22346.rs b/src/test/run-pass/issue-22346.rs
new file mode 100644 (file)
index 0000000..8538950
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+// pretty-expanded FIXME #23616
+
+#![feature(core)]
+
+// This used to cause an ICE because the retslot for the "return" had the wrong type
+fn testcase<'a>() -> Box<Iterator<Item=usize> + 'a> {
+    return Box::new((0..3).map(|i| { return i; }));
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-24353.rs b/src/test/run-pass/issue-24353.rs
new file mode 100644 (file)
index 0000000..7a41a01
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+fn main() {
+    return ();
+
+    let x = ();
+    x
+}
diff --git a/src/test/run-pass/issue-26127.rs b/src/test/run-pass/issue-26127.rs
new file mode 100644 (file)
index 0000000..75cbcc8
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+trait Tr { type T; }
+impl Tr for u8 { type T=(); }
+struct S<I: Tr>(I::T);
+
+fn foo<I: Tr>(i: I::T) {
+    S::<I>(i);
+}
+
+fn main() {
+    foo::<u8>(());
+}
diff --git a/src/test/run-pass/issue-29927.rs b/src/test/run-pass/issue-29927.rs
new file mode 100644 (file)
index 0000000..6d9adbc
--- /dev/null
@@ -0,0 +1,20 @@
+// 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)]
+struct A {
+    field: usize,
+}
+const fn f() -> usize {
+    5
+}
+fn main() {
+    let _ = [0; f()];
+}
diff --git a/src/test/run-pass/issue-32947.rs b/src/test/run-pass/issue-32947.rs
new file mode 100644 (file)
index 0000000..d0fef36
--- /dev/null
@@ -0,0 +1,31 @@
+// 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(repr_simd, test)]
+
+extern crate test;
+
+#[repr(simd)]
+pub struct Mu64(pub u64, pub u64, pub u64, pub u64);
+
+fn main() {
+    // This ensures an unaligned pointer even in optimized builds, though LLVM
+    // gets enough type information to actually not mess things up in that case,
+    // but at the time of writing this, it's enough to trigger the bug in
+    // non-optimized builds
+    unsafe {
+        let memory = &mut [0u64; 8] as *mut _ as *mut u8;
+        let misaligned_ptr: &mut [u8; 32] = {
+            std::mem::transmute(memory.offset(1))
+        };
+        *misaligned_ptr = std::mem::transmute(Mu64(1, 1, 1, 1));
+        test::black_box(memory);
+    }
+}
diff --git a/src/test/run-pass/issue-33187.rs b/src/test/run-pass/issue-33187.rs
new file mode 100644 (file)
index 0000000..477112a
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+struct Foo<A: Repr>(<A as Repr>::Data);
+
+impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy { }
+impl<A> Clone for Foo<A> where <A as Repr>::Data: Clone {
+    fn clone(&self) -> Self { Foo(self.0.clone()) }
+}
+
+trait Repr {
+    type Data;
+}
+
+impl<A> Repr for A {
+    type Data = u32;
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-34569.rs b/src/test/run-pass/issue-34569.rs
new file mode 100644 (file)
index 0000000..41d02e9
--- /dev/null
@@ -0,0 +1,26 @@
+// 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:-g
+
+// In this test we just want to make sure that the code below does not lead to
+// a debuginfo verification assertion during compilation. This was caused by the
+// closure in the guard being translated twice due to how match expressions are
+// handled.
+//
+// See https://github.com/rust-lang/rust/issues/34569 for details.
+
+fn main() {
+    match 0 {
+        e if (|| { e == 0 })() => {},
+        1 => {},
+        _ => {}
+    }
+}
diff --git a/src/test/run-pass/issue-34796.rs b/src/test/run-pass/issue-34796.rs
new file mode 100644 (file)
index 0000000..0fb6ccc
--- /dev/null
@@ -0,0 +1,36 @@
+// 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.
+
+// This test case exposes conditions where the encoding of a trait object type
+// with projection predicates would differ between this crate and the upstream
+// crate, because the predicates were encoded in different order within each
+// crate. This led to different symbol hashes of functions using these type,
+// which in turn led to linker errors because the two crates would not agree on
+// the symbol name.
+// The fix was to make the order in which predicates get encoded stable.
+
+// aux-build:issue34796aux.rs
+extern crate issue34796aux;
+
+fn mk<T>() -> T { loop {} }
+
+struct Data<T, E> {
+    data: T,
+    error: E,
+}
+
+fn main() {
+    issue34796aux::bar(|()| {
+        Data::<(), std::io::Error> {
+            data: mk(),
+            error: mk(),
+        }
+    })
+}
diff --git a/src/test/run-pass/issue-36260.rs b/src/test/run-pass/issue-36260.rs
new file mode 100644 (file)
index 0000000..08dbbb5
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// Make sure this compiles without getting a linker error because of missing
+// drop-glue because the collector missed adding drop-glue for the closure:
+
+fn create_fn() -> Box<Fn()> {
+    let text = String::new();
+
+    Box::new(move || { let _ = &text; })
+}
+
+fn main() {
+    let _ = create_fn();
+}
diff --git a/src/test/run-pass/issue-37991.rs b/src/test/run-pass/issue-37991.rs
new file mode 100644 (file)
index 0000000..cacc653
--- /dev/null
@@ -0,0 +1,20 @@
+// 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(const_fn)]
+
+const fn foo() -> i64 {
+    3
+}
+
+fn main() {
+    let val = &(foo() % 2);
+    assert_eq!(*val, 1);
+}
diff --git a/src/test/run-pass/issue-38715.rs b/src/test/run-pass/issue-38715.rs
new file mode 100644 (file)
index 0000000..054785e
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+// aux-build:issue_38715.rs
+
+// Test that `#[macro_export] macro_rules!` shadow earlier `#[macro_export] macro_rules!`
+
+#[macro_use]
+extern crate issue_38715;
+
+fn main() {
+    foo!();
+}
diff --git a/src/test/run-pass/issue-38727.rs b/src/test/run-pass/issue-38727.rs
new file mode 100644 (file)
index 0000000..e60b6a9
--- /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.
+
+#[repr(u64)]
+enum A {
+    A = 0u64,
+    B = !0u64,
+}
+
+fn cmp() -> A {
+    A::B
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue18173.rs b/src/test/run-pass/issue18173.rs
deleted file mode 100644 (file)
index f4266fa..0000000
+++ /dev/null
@@ -1,21 +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.
-
-trait Foo {
-    type T;
-}
-
-// should be able to use a trait with an associated type without specifying it as an argument
-trait Bar<F: Foo> {
-    fn bar(foo: &F);
-}
-
-pub fn main() {
-}
diff --git a/src/test/run-pass/issue22008.rs b/src/test/run-pass/issue22008.rs
deleted file mode 100644 (file)
index 3e14512..0000000
+++ /dev/null
@@ -1,18 +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.
-
-pub fn main() {
-    let command = "a";
-
-    match command {
-        "foo" => println!("foo"),
-        _     => println!("{}", command),
-    }
-}
diff --git a/src/test/run-pass/issue22346.rs b/src/test/run-pass/issue22346.rs
deleted file mode 100644 (file)
index 8538950..0000000
+++ /dev/null
@@ -1,21 +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.
-
-// pretty-expanded FIXME #23616
-
-#![feature(core)]
-
-// This used to cause an ICE because the retslot for the "return" had the wrong type
-fn testcase<'a>() -> Box<Iterator<Item=usize> + 'a> {
-    return Box::new((0..3).map(|i| { return i; }));
-}
-
-fn main() {
-}
diff --git a/src/test/run-pass/issue24353.rs b/src/test/run-pass/issue24353.rs
deleted file mode 100644 (file)
index 7a41a01..0000000
+++ /dev/null
@@ -1,16 +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.
-
-fn main() {
-    return ();
-
-    let x = ();
-    x
-}
diff --git a/src/test/run-pass/issue26127.rs b/src/test/run-pass/issue26127.rs
deleted file mode 100644 (file)
index 75cbcc8..0000000
+++ /dev/null
@@ -1,21 +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.
-
-trait Tr { type T; }
-impl Tr for u8 { type T=(); }
-struct S<I: Tr>(I::T);
-
-fn foo<I: Tr>(i: I::T) {
-    S::<I>(i);
-}
-
-fn main() {
-    foo::<u8>(());
-}
diff --git a/src/test/run-pass/issue29927.rs b/src/test/run-pass/issue29927.rs
deleted file mode 100644 (file)
index 6d9adbc..0000000
+++ /dev/null
@@ -1,20 +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.
-
-#![feature(const_fn)]
-struct A {
-    field: usize,
-}
-const fn f() -> usize {
-    5
-}
-fn main() {
-    let _ = [0; f()];
-}
diff --git a/src/test/run-pass/issue34569.rs b/src/test/run-pass/issue34569.rs
deleted file mode 100644 (file)
index 41d02e9..0000000
+++ /dev/null
@@ -1,26 +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.
-
-// compile-flags:-g
-
-// In this test we just want to make sure that the code below does not lead to
-// a debuginfo verification assertion during compilation. This was caused by the
-// closure in the guard being translated twice due to how match expressions are
-// handled.
-//
-// See https://github.com/rust-lang/rust/issues/34569 for details.
-
-fn main() {
-    match 0 {
-        e if (|| { e == 0 })() => {},
-        1 => {},
-        _ => {}
-    }
-}
diff --git a/src/test/run-pass/issue34796.rs b/src/test/run-pass/issue34796.rs
deleted file mode 100644 (file)
index 0fb6ccc..0000000
+++ /dev/null
@@ -1,36 +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.
-
-// This test case exposes conditions where the encoding of a trait object type
-// with projection predicates would differ between this crate and the upstream
-// crate, because the predicates were encoded in different order within each
-// crate. This led to different symbol hashes of functions using these type,
-// which in turn led to linker errors because the two crates would not agree on
-// the symbol name.
-// The fix was to make the order in which predicates get encoded stable.
-
-// aux-build:issue34796aux.rs
-extern crate issue34796aux;
-
-fn mk<T>() -> T { loop {} }
-
-struct Data<T, E> {
-    data: T,
-    error: E,
-}
-
-fn main() {
-    issue34796aux::bar(|()| {
-        Data::<(), std::io::Error> {
-            data: mk(),
-            error: mk(),
-        }
-    })
-}
diff --git a/src/test/run-pass/issue36260.rs b/src/test/run-pass/issue36260.rs
deleted file mode 100644 (file)
index 08dbbb5..0000000
+++ /dev/null
@@ -1,22 +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.
-
-// Make sure this compiles without getting a linker error because of missing
-// drop-glue because the collector missed adding drop-glue for the closure:
-
-fn create_fn() -> Box<Fn()> {
-    let text = String::new();
-
-    Box::new(move || { let _ = &text; })
-}
-
-fn main() {
-    let _ = create_fn();
-}
diff --git a/src/test/run-pass/stdio-is-blocking.rs b/src/test/run-pass/stdio-is-blocking.rs
new file mode 100644 (file)
index 0000000..74170ca
--- /dev/null
@@ -0,0 +1,90 @@
+// 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::env;
+use std::io::prelude::*;
+use std::process::Command;
+use std::thread;
+
+const THREADS: usize = 20;
+const WRITES: usize = 100;
+const WRITE_SIZE: usize = 1024 * 32;
+
+fn main() {
+    let args = env::args().collect::<Vec<_>>();
+    if args.len() == 1 {
+        parent();
+    } else {
+        child();
+    }
+}
+
+fn parent() {
+    let me = env::current_exe().unwrap();
+    let mut cmd = Command::new(me);
+    cmd.arg("run-the-test");
+    let output = cmd.output().unwrap();
+    assert!(output.status.success());
+    assert_eq!(output.stderr.len(), 0);
+    assert_eq!(output.stdout.len(), WRITES * THREADS * WRITE_SIZE);
+    for byte in output.stdout.iter() {
+        assert_eq!(*byte, b'a');
+    }
+}
+
+fn child() {
+    let threads = (0..THREADS).map(|_| {
+        thread::spawn(|| {
+            let buf = [b'a'; WRITE_SIZE];
+            for _ in 0..WRITES {
+                write_all(&buf);
+            }
+        })
+    }).collect::<Vec<_>>();
+
+    for thread in threads {
+        thread.join().unwrap();
+    }
+}
+
+#[cfg(unix)]
+fn write_all(buf: &[u8]) {
+    use std::fs::File;
+    use std::mem;
+    use std::os::unix::prelude::*;
+
+    let mut file = unsafe { File::from_raw_fd(1) };
+    let res = file.write_all(buf);
+    mem::forget(file);
+    res.unwrap();
+}
+
+#[cfg(windows)]
+fn write_all(buf: &[u8]) {
+    use std::fs::File;
+    use std::mem;
+    use std::os::windows::raw::*;
+    use std::os::windows::prelude::*;
+
+    const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32;
+
+    extern "system" {
+        fn GetStdHandle(handle: u32) -> HANDLE;
+    }
+
+    let mut file = unsafe {
+        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+        assert!(!handle.is_null());
+        File::from_raw_handle(handle)
+    };
+    let res = file.write_all(buf);
+    mem::forget(file);
+    res.unwrap();
+}
diff --git a/src/test/run-pass/test-allow-dead-extern-static-no-warning.rs b/src/test/run-pass/test-allow-dead-extern-static-no-warning.rs
new file mode 100644 (file)
index 0000000..8df32b5
--- /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: --test
+
+#![deny(dead_code)]
+
+extern "C" {
+    #[allow(dead_code)]
+    static Qt: u64;
+}
+
+fn main() {}
index d138e09318bfe3ce1b1ae681041cc658f0732b24..53d726f1f663bbd418d7679435963a601d7a9231 100644 (file)
 
 // ignore-stage0
 // ignore-stage1
-#![feature(i128_type)]
+#![feature(i128_type, test)]
+
+extern crate test;
+use test::black_box as b;
 
 fn main() {
     let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF;
@@ -63,5 +66,15 @@ fn main() {
         format!("{}", u128::max_value()));
     assert_eq!("147573952589676412928", format!("{:?}", j));
     // common traits
-    x.clone();
+    assert_eq!(x, b(x.clone()));
+    // overflow checks
+    assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521));
+    assert_eq!((k).checked_mul(k), None);
+    let l: u128 = b(u128::max_value() - 10);
+    let o: u128 = b(17);
+    assert_eq!(l.checked_add(b(11)), None);
+    assert_eq!(l.checked_sub(l), Some(0));
+    assert_eq!(o.checked_sub(b(18)), None);
+    assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127));
+    assert_eq!(o.checked_shl(b(128)), None);
 }
index fe80a90955045938b48a38f8de4ebd708d354bb5..dc28732b55ee2a5f1824260524dc6ccd80abfe25 100644 (file)
@@ -10,8 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
-#![feature(proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index 66069c7a86a344a25a7c26cdce8bb5c842756f47..0aafe3f17b3d0f6310b30d10baedc9eb00d19cef 100644 (file)
@@ -4,11 +4,11 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more n
 20 |     match (A, ()) {
    |           ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
 
-error[E0004]: non-exhaustive patterns: `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
+error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
   --> $DIR/issue-35609.rs:24:11
    |
 24 |     match (A, A) {
-   |           ^^^^^^ patterns `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
+   |           ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:28:11
diff --git a/src/test/ui/span/E0204.rs b/src/test/ui/span/E0204.rs
new file mode 100644 (file)
index 0000000..9fb3760
--- /dev/null
@@ -0,0 +1,36 @@
+// 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.
+
+struct Foo {
+    foo: Vec<u32>,
+}
+
+impl Copy for Foo { }
+
+#[derive(Copy)]
+struct Foo2<'a> {
+    ty: &'a mut bool,
+}
+
+enum EFoo {
+    Bar { x: Vec<u32> },
+    Baz,
+}
+
+impl Copy for EFoo { }
+
+#[derive(Copy)]
+enum EFoo2<'a> {
+    Bar(&'a mut bool),
+    Baz,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr
new file mode 100644 (file)
index 0000000..81a60a9
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:15:6
+   |
+12 |     foo: Vec<u32>,
+   |     ------------- this field does not implement `Copy`
+...
+15 | impl Copy for Foo { }
+   |      ^^^^
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:27:6
+   |
+23 |     Bar { x: Vec<u32> },
+   |           ----------- this field does not implement `Copy`
+...
+27 | impl Copy for EFoo { }
+   |      ^^^^
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:17:10
+   |
+17 | #[derive(Copy)]
+   |          ^^^^
+18 | struct Foo2<'a> {
+19 |     ty: &'a mut bool,
+   |     ---------------- this field does not implement `Copy`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:29:10
+   |
+29 | #[derive(Copy)]
+   |          ^^^^
+30 | enum EFoo2<'a> {
+31 |     Bar(&'a mut bool),
+   |         ------------- this field does not implement `Copy`
+
+error: aborting due to 4 previous errors
+