]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #47922 - zackmdavis:and_the_case_of_the_unused_field_pattern, r=estebank
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 7 Feb 2018 16:30:52 +0000 (08:30 -0800)
committerGitHub <noreply@github.com>
Wed, 7 Feb 2018 16:30:52 +0000 (08:30 -0800)
correct unused field pattern suggestions

![unused_field_pattern_local](https://user-images.githubusercontent.com/1076988/35662336-7a69488a-06cc-11e8-9901-8d22b5cf924f.png)

r? @estebank

235 files changed:
config.toml.example
src/Cargo.lock
src/bootstrap/Cargo.toml
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/test.rs
src/ci/docker/x86_64-gnu-tools/checktools.sh
src/ci/run.sh
src/doc/book
src/doc/reference
src/doc/unstable-book/src/language-features/lang-items.md
src/doc/unstable-book/src/language-features/match-beginning-vert.md [deleted file]
src/doc/unstable-book/src/language-features/use-nested-groups.md [deleted file]
src/etc/wasm32-shim.js
src/libcore/any.rs
src/libcore/convert.rs
src/libcore/fmt/mod.rs
src/libcore/intrinsics.rs
src/libcore/iter/iterator.rs
src/libcore/iter/range.rs
src/libcore/lib.rs
src/libcore/mem.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/ops/arith.rs
src/libcore/ops/bit.rs
src/libcore/ptr.rs
src/libcore/tests/iter.rs
src/libproc_macro/lib.rs
src/librustc/diagnostics.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/note.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/lint/context.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/mir/mod.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/coherence.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/mod.rs
src/librustc/traits/on_unimplemented.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc/traits/structural_impls.rs
src/librustc/ty/layout.rs
src/librustc/ty/sty.rs
src/librustc_binaryen/BinaryenWrapper.cpp
src/librustc_binaryen/lib.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/borrowck/unused.rs
src/librustc_const_eval/eval.rs
src/librustc_driver/driver.rs
src/librustc_errors/diagnostic.rs
src/librustc_errors/diagnostic_builder.rs
src/librustc_errors/lib.rs
src/librustc_errors/snippet.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/type_check/liveness.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/dataflow/impls/borrowed_locals.rs [new file with mode: 0644]
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/interpret/const_eval.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_passes/loops.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/back/write.rs
src/librustc_trans/context.rs
src/librustc_trans/mir/constant.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/generator_interior.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/dark.css
src/libstd/Cargo.toml
src/libstd/f32.rs
src/libstd/ffi/c_str.rs
src/libstd/fs.rs
src/libstd/lib.rs
src/libstd/os/raw.rs [deleted file]
src/libstd/os/raw/char.md [new file with mode: 0644]
src/libstd/os/raw/double.md [new file with mode: 0644]
src/libstd/os/raw/float.md [new file with mode: 0644]
src/libstd/os/raw/int.md [new file with mode: 0644]
src/libstd/os/raw/long.md [new file with mode: 0644]
src/libstd/os/raw/longlong.md [new file with mode: 0644]
src/libstd/os/raw/mod.rs [new file with mode: 0644]
src/libstd/os/raw/schar.md [new file with mode: 0644]
src/libstd/os/raw/short.md [new file with mode: 0644]
src/libstd/os/raw/uchar.md [new file with mode: 0644]
src/libstd/os/raw/uint.md [new file with mode: 0644]
src/libstd/os/raw/ulong.md [new file with mode: 0644]
src/libstd/os/raw/ulonglong.md [new file with mode: 0644]
src/libstd/os/raw/ushort.md [new file with mode: 0644]
src/libstd/panic.rs
src/libstd/sys/cloudabi/thread.rs
src/libstd/sys/redox/thread.rs
src/libstd/sys/unix/stack_overflow.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/wasm/args.rs
src/libstd/sys/wasm/mod.rs
src/libstd/sys/wasm/os.rs
src/libstd/sys/wasm/stdio.rs
src/libstd/sys/wasm/thread.rs
src/libstd/sys/wasm/time.rs
src/libstd/sys/windows/thread.rs
src/libstd/sys_common/thread_info.rs
src/libsyntax/ast.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/build.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/json.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax_ext/asm.rs
src/libsyntax_ext/deriving/encodable.rs
src/libsyntax_pos/lib.rs
src/libtest/lib.rs
src/test/codegen/no-output-asm-is-volatile.rs [new file with mode: 0644]
src/test/codegen/stack-probes.rs
src/test/compile-fail/E0195.rs
src/test/compile-fail/absolute-paths-in-nested-use-groups.rs
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/const-typeid-of.rs [new file with mode: 0644]
src/test/compile-fail/issue-16048.rs
src/test/compile-fail/issue-42344.rs [new file with mode: 0644]
src/test/compile-fail/issue-44415.rs [new file with mode: 0644]
src/test/compile-fail/issue-46604.rs
src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs [new file with mode: 0644]
src/test/compile-fail/nll/reference-carried-through-struct-field.rs
src/test/compile-fail/regions-bound-missing-bound-in-impl.rs [deleted file]
src/test/compile-fail/ufcs-qpath-self-mismatch.rs
src/test/mir-opt/validate_5.rs
src/test/parse-fail/bad-char-literals.rs
src/test/parse-fail/lex-stray-backslash.rs [new file with mode: 0644]
src/test/run-make/output-filename-conflicts-with-directory/Makefile [new file with mode: 0644]
src/test/run-make/output-filename-conflicts-with-directory/foo.rs [new file with mode: 0644]
src/test/run-make/output-filename-overwrites-input/Makefile
src/test/run-make/output-filename-overwrites-input/bar.rs [new file with mode: 0644]
src/test/run-make/output-filename-overwrites-input/foo.rs
src/test/run-make/save-analysis-fail/foo.rs
src/test/run-make/save-analysis/extra-docs.md [new file with mode: 0644]
src/test/run-make/save-analysis/foo.rs
src/test/run-pass/const-typeid-of.rs [new file with mode: 0644]
src/test/run-pass/generator/too-live-local-in-immovable-gen.rs [new file with mode: 0644]
src/test/run-pass/issue-47139-1.rs [new file with mode: 0644]
src/test/run-pass/issue-47139-2.rs [new file with mode: 0644]
src/test/run-pass/issue-47673.rs
src/test/run-pass/issue-47722.rs [new file with mode: 0644]
src/test/run-pass/issue-47789.rs [new file with mode: 0644]
src/test/run-pass/match-beginning-vert.rs [new file with mode: 0644]
src/test/run-pass/nll/issue-47589.rs [new file with mode: 0644]
src/test/run-pass/stack-probes-lto.rs
src/test/run-pass/stack-probes.rs
src/test/run-pass/use-nested-groups.rs
src/test/rustdoc/const-evalutation-ice.rs [new file with mode: 0644]
src/test/rustdoc/issue-47639.rs [new file with mode: 0644]
src/test/ui/associated-const-impl-wrong-lifetime.stderr
src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs [new file with mode: 0644]
src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr [new file with mode: 0644]
src/test/ui/closure-expected-type/expect-region-supply-region.stderr
src/test/ui/feature-gate-match_beginning_vert.rs [deleted file]
src/test/ui/feature-gate-match_beginning_vert.stderr [deleted file]
src/test/ui/feature-gate-use_nested_groups.rs [deleted file]
src/test/ui/feature-gate-use_nested_groups.stderr [deleted file]
src/test/ui/generator/generator-with-nll.stderr
src/test/ui/generator/pattern-borrow.rs [new file with mode: 0644]
src/test/ui/generator/pattern-borrow.stderr [new file with mode: 0644]
src/test/ui/generator/sized-yield.rs [new file with mode: 0644]
src/test/ui/generator/sized-yield.stderr [new file with mode: 0644]
src/test/ui/generator/yield-while-local-borrowed.stderr
src/test/ui/impl-trait/equality.rs
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/trait_type.stderr
src/test/ui/in-band-lifetimes/ellided-lifetimes.rs [new file with mode: 0644]
src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr [new file with mode: 0644]
src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs [new file with mode: 0644]
src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr [new file with mode: 0644]
src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
src/test/ui/issue-27942.stderr
src/test/ui/issue-37884.stderr
src/test/ui/issue-45697-1.rs [new file with mode: 0644]
src/test/ui/issue-45697-1.stderr [new file with mode: 0644]
src/test/ui/issue-45697.rs [new file with mode: 0644]
src/test/ui/issue-45697.stderr [new file with mode: 0644]
src/test/ui/issue-46472.stderr
src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs [new file with mode: 0644]
src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr [new file with mode: 0644]
src/test/ui/lint/suggestions.rs
src/test/ui/lint/suggestions.stderr
src/test/ui/loop-break-value-no-repeat.stderr
src/test/ui/macros/span-covering-argument-1.rs [new file with mode: 0644]
src/test/ui/macros/span-covering-argument-1.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/binops.rs
src/test/ui/mismatched_types/binops.stderr
src/test/ui/on-unimplemented/auxiliary/no_debug.rs [new file with mode: 0644]
src/test/ui/on-unimplemented/no-debug.rs [new file with mode: 0644]
src/test/ui/on-unimplemented/no-debug.stderr [new file with mode: 0644]
src/test/ui/span/macro-span-replacement.stderr
src/test/ui/span/multiline-span-simple.rs
src/test/ui/span/multiline-span-simple.stderr
src/test/ui/static-lifetime.stderr
src/test/ui/suggestions/for-c-in-str.stderr
src/test/ui/use-nested-groups-error.rs
src/test/ui/use-nested-groups-error.stderr
src/tools/clippy
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/rls
src/tools/rustbook/Cargo.toml
src/tools/rustbook/src/main.rs
src/tools/rustfmt
src/tools/tidy/src/deps.rs

index 1d60d8c949441527c16b6f4eda11ca832186aaf2..c2ec731eeb8a20b5bc61e605096da19e05865995 100644 (file)
 # compiler.
 #codegen-units = 1
 
+# Whether to enable ThinLTO (and increase the codegen units to either a default
+# or the configured value). On by default. If we want the fastest possible
+# compiler, we should disable this.
+#thinlto = true
+
 # Whether or not debug assertions are enabled for the compiler and standard
 # library. Also enables compilation of debug! and trace! logging macros.
 #debug-assertions = false
 
 # Flag indicating whether git info will be retrieved from .git automatically.
 # Having the git information can cause a lot of rebuilds during development.
-# Note: If this attribute is not explicity set (e.g. if left commented out) it
+# Note: If this attribute is not explicitly set (e.g. if left commented out) it
 # will default to true if channel = "dev", but will default to false otherwise.
 #ignore-git = true
 
 # bootstrap)
 #codegen-backends = ["llvm"]
 
+# Flag indicating whether `libstd` calls an imported function to handle basic IO
+# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
+# target, as without this option the test output will not be captured.
+#wasm-syscall = false
+
 # =============================================================================
 # Options for specific targets
 #
 #linker = "cc"
 
 # Path to the `llvm-config` binary of the installation of a custom LLVM to link
-# against. Note that if this is specifed we don't compile LLVM at all for this
+# against. Note that if this is specified we don't compile LLVM at all for this
 # target.
 #llvm-config = "../path/to/llvm/root/bin/llvm-config"
 
index d26098903eec5a05931545f94a6a665c149c9290..52ed134c01ecda147203abd9c8fd9e2493641113 100644 (file)
@@ -133,6 +133,7 @@ dependencies = [
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -291,14 +292,14 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.0.174"
+version = "0.0.186"
 dependencies = [
  "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy-mini-macro-test 0.1.0",
- "clippy_lints 0.0.174",
- "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy-mini-macro-test 0.2.0",
+ "clippy_lints 0.0.186",
+ "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -306,15 +307,15 @@ dependencies = [
 
 [[package]]
 name = "clippy-mini-macro-test"
-version = "0.1.0"
+version = "0.2.0"
 
 [[package]]
 name = "clippy_lints"
-version = "0.0.174"
+version = "0.0.186"
 dependencies = [
  "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -386,7 +387,7 @@ dependencies = [
 
 [[package]]
 name = "compiletest_rs"
-version = "0.3.3"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -928,6 +929,11 @@ dependencies = [
  "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "is-match"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "itertools"
 version = "0.6.5"
@@ -936,6 +942,14 @@ dependencies = [
  "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "itoa"
 version = "0.3.4"
@@ -1129,23 +1143,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "mdbook"
-version = "0.0.28"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
+ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1190,7 +1209,7 @@ version = "0.1.0"
 dependencies = [
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1618,7 +1637,7 @@ version = "0.1.0"
 
 [[package]]
 name = "rls"
-version = "0.124.0"
+version = "0.125.0"
 dependencies = [
  "cargo 0.26.0",
  "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1635,7 +1654,7 @@ dependencies = [
  "rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.3.6",
+ "rustfmt-nightly 0.3.8",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1695,7 +1714,7 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1723,7 +1742,7 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_cratesio_shim"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1732,57 +1751,57 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-ap-serialize"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rustc-ap-syntax"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-ap-syntax_pos"
-version = "12.0.0"
+version = "29.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2207,7 +2226,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "0.3.6"
+version = "0.3.8"
 dependencies = [
  "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2219,8 +2238,8 @@ dependencies = [
  "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2379,6 +2398,11 @@ name = "shell-escape"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "shlex"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "siphasher"
 version = "0.2.2"
@@ -2702,6 +2726,18 @@ dependencies = [
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "toml-query"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.4"
@@ -2941,7 +2977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
 "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
 "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
-"checksum compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "562bafeec9aef1e3e08f1c5b0c542220bb80ff2894e5373a1f9d17c346412c66"
+"checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc"
 "checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e"
 "checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"
 "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"
@@ -2992,7 +3028,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8"
 "checksum ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb2f0238094bd1b41800fb6eb9b16fdd5e9832ed6053ed91409f0cd5bf28dcfd"
+"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
 "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"
+"checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394"
 "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
 "checksum jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "565f6106bd87b394398f813bea4e5ecad6d6b0f6aa077592d088f882a506481d"
 "checksum json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)" = "39ebf0fac977ee3a4a3242b6446004ff64514889e3e2730bbd4f764a67a2e483"
@@ -3014,7 +3052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
 "checksum markup5ever 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "047150a0e03b57e638fc45af33a0b63a0362305d5b9f92ecef81df472a4cceb0"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "1ee8ba20c002000546681dc78d7f7e91fd35832058b1e2fdd492ca842bb6e9be"
+"checksum mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fef236caad7ba3b5b3944df946f19ab3e190bca53c111dd00fe05fa8d879f2fd"
 "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
 "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
@@ -3068,12 +3106,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2"
 "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
 "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
-"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e"
-"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc"
-"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0"
-"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604"
-"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c"
-"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b"
+"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
+"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad"
+"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182"
+"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b"
+"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d"
+"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0"
 "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
 "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
@@ -3094,6 +3132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
 "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc"
 "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
+"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
 "checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
 "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
@@ -3122,6 +3161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
 "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
 "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
+"checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
 "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
 "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
 "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
index bbbbf0e1915555c419039a827eb1703a8c267c4e..2d478341317848250c1b2a98571a9d67329480a7 100644 (file)
@@ -41,3 +41,4 @@ serde_derive = "1.0.8"
 serde_json = "1.0.2"
 toml = "0.4"
 lazy_static = "0.2"
+time = "0.1"
index 780513dd943946853c7085980219fd85c5778729..bf7b1015a49214a95a381981494842d90141c13c 100644 (file)
@@ -509,10 +509,6 @@ pub fn cargo(&self,
              })
              .env("TEST_MIRI", self.config.test_miri.to_string())
              .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
-        if let Some(n) = self.config.rust_codegen_units {
-            cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
-        }
-
 
         if let Some(host_linker) = self.build.linker(compiler.host) {
             cargo.env("RUSTC_HOST_LINKER", host_linker);
@@ -679,6 +675,13 @@ pub fn cargo(&self,
         if self.is_very_verbose() {
             cargo.arg("-v");
         }
+
+        // This must be kept before the thinlto check, as we set codegen units
+        // to 1 forcibly there.
+        if let Some(n) = self.config.rust_codegen_units {
+            cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
+        }
+
         if self.config.rust_optimize {
             // FIXME: cargo bench does not accept `--release`
             if cmd != "bench" {
@@ -686,11 +689,17 @@ pub fn cargo(&self,
             }
 
             if self.config.rust_codegen_units.is_none() &&
-               self.build.is_rust_llvm(compiler.host)
-            {
+               self.build.is_rust_llvm(compiler.host) &&
+               self.config.rust_thinlto {
                 cargo.env("RUSTC_THINLTO", "1");
+            } else if self.config.rust_codegen_units.is_none() {
+                // Generally, if ThinLTO has been disabled for some reason, we
+                // want to set the codegen units to 1. However, we shouldn't do
+                // this if the option was specifically set by the user.
+                cargo.env("RUSTC_CODEGEN_UNITS", "1");
             }
         }
+
         if self.config.locked_deps {
             cargo.arg("--locked");
         }
index dbeb27cbfb7d36d5b1f8e377da977f86a7af37bf..be8910120ee19051545e4e1dab81374738d58355 100644 (file)
@@ -81,6 +81,7 @@ pub struct Config {
     // rust codegen options
     pub rust_optimize: bool,
     pub rust_codegen_units: Option<u32>,
+    pub rust_thinlto: bool,
     pub rust_debug_assertions: bool,
     pub rust_debuginfo: bool,
     pub rust_debuginfo_lines: bool,
@@ -107,6 +108,7 @@ pub struct Config {
     pub debug_jemalloc: bool,
     pub use_jemalloc: bool,
     pub backtrace: bool, // support for RUST_BACKTRACE
+    pub wasm_syscall: bool,
 
     // misc
     pub low_priority: bool,
@@ -260,6 +262,7 @@ fn default() -> StringOrBool {
 struct Rust {
     optimize: Option<bool>,
     codegen_units: Option<u32>,
+    thinlto: Option<bool>,
     debug_assertions: Option<bool>,
     debuginfo: Option<bool>,
     debuginfo_lines: Option<bool>,
@@ -282,6 +285,7 @@ struct Rust {
     test_miri: Option<bool>,
     save_toolstates: Option<String>,
     codegen_backends: Option<Vec<String>>,
+    wasm_syscall: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -410,6 +414,7 @@ pub fn parse(args: &[String]) -> Config {
 
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
+        let mut thinlto = None;
         let mut llvm_assertions = None;
         let mut debuginfo_lines = None;
         let mut debuginfo_only_std = None;
@@ -453,6 +458,7 @@ pub fn parse(args: &[String]) -> Config {
             optimize = rust.optimize;
             ignore_git = rust.ignore_git;
             debug_jemalloc = rust.debug_jemalloc;
+            thinlto = rust.thinlto;
             set(&mut config.rust_optimize_tests, rust.optimize_tests);
             set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
             set(&mut config.codegen_tests, rust.codegen_tests);
@@ -463,6 +469,7 @@ pub fn parse(args: &[String]) -> Config {
             set(&mut config.rust_dist_src, rust.dist_src);
             set(&mut config.quiet_tests, rust.quiet_tests);
             set(&mut config.test_miri, rust.test_miri);
+            set(&mut config.wasm_syscall, rust.wasm_syscall);
             config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
             config.rustc_default_linker = rust.default_linker.clone();
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
@@ -536,6 +543,7 @@ pub fn parse(args: &[String]) -> Config {
             "stable" | "beta" | "nightly" => true,
             _ => false,
         };
+        config.rust_thinlto = thinlto.unwrap_or(true);
         config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
         config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
 
index bc6f666d0012f5d2aa0930fff2743d5724375abc..d51752a12d9e56928b8eda1aab606b8cb758d2eb 100755 (executable)
@@ -70,6 +70,7 @@ o("emscripten", None, "compile the emscripten backend as well as LLVM")
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
 o("optimize", "rust.optimize", "build optimized rust code")
+o("thinlto", "rust.thinlto", "build Rust with ThinLTO enabled")
 o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
index dbb7d19e43285089515cb0c0878214ccc7181b13..6717b1cb0988389aea57ef0d4cefa6350f479611 100644 (file)
@@ -33,6 +33,7 @@
 use compile;
 use tool::{self, Tool};
 use cache::{INTERNER, Interned};
+use time;
 
 pub fn pkgname(build: &Build, component: &str) -> String {
     if component == "cargo" {
@@ -445,8 +446,7 @@ fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
             t!(fs::create_dir_all(image.join("share/man/man1")));
             let man_src = build.src.join("src/doc/man");
             let man_dst = image.join("share/man/man1");
-            let date_output = output(Command::new("date").arg("+%B %Y"));
-            let month_year = date_output.trim();
+            let month_year = t!(time::strftime("%B %Y", &time::now()));
             // don't use our `bootstrap::util::{copy, cp_r}`, because those try
             // to hardlink, and we don't want to edit the source templates
             for entry_result in t!(fs::read_dir(man_src)) {
@@ -456,7 +456,7 @@ fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
                 t!(fs::copy(&page_src, &page_dst));
                 // template in month/year and version number
                 replace_in_file(&page_dst,
-                                &[("<INSERT DATE HERE>", month_year),
+                                &[("<INSERT DATE HERE>", &month_year),
                                   ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
             }
 
index aae0a4f056f08b9ef32ce2f3dde7dd740c1f8912..a84a6a8990bbd992007680df29acd344cb8775b3 100644 (file)
 extern crate getopts;
 extern crate num_cpus;
 extern crate toml;
+extern crate time;
 
 #[cfg(unix)]
 extern crate libc;
@@ -423,6 +424,9 @@ fn std_features(&self) -> String {
         if self.config.profiler {
             features.push_str(" profiler");
         }
+        if self.config.wasm_syscall {
+            features.push_str(" wasm_syscall");
+        }
         features
     }
 
index a316b0f7ef91b7ef1da39d9c64a6bc212b66e141..e4c1cdb79fd24e4d72616553fa1a3ccafdfc44bc 100644 (file)
@@ -610,7 +610,6 @@ fn run(self, builder: &Builder) {
         mode: "incremental",
         suite: "incremental-fulldeps",
     },
-    Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
     Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" },
 
     Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" },
@@ -619,6 +618,7 @@ fn run(self, builder: &Builder) {
     Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" },
     Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" },
     Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" },
+    Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
 ];
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -1286,6 +1286,14 @@ fn run(self, builder: &Builder) {
             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
                       build.config.nodejs.as_ref().expect("nodejs not configured"));
         } else if target.starts_with("wasm32") {
+            // Warn about running tests without the `wasm_syscall` feature enabled.
+            // The javascript shim implements the syscall interface so that test
+            // output can be correctly reported.
+            if !build.config.wasm_syscall {
+                println!("Libstd was built without `wasm_syscall` feature enabled: \
+                          test output may not be visible.");
+            }
+
             // On the wasm32-unknown-unknown target we're using LTO which is
             // incompatible with `-C prefer-dynamic`, so disable that here
             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
index b9268fe62ed06b44825711aa1f6742fcb2f4fa51..61bb5a84d21ac150e5f15cb7e7e9610d4ab6debb 100755 (executable)
@@ -32,7 +32,7 @@ cat "$TOOLSTATE_FILE"
 
 # If this PR is intended to update one of these tools, do not let the build pass
 # when they do not test-pass.
-for TOOL in rls rustfmt miri clippy; do
+for TOOL in rls rustfmt clippy; do
     echo "Verifying status of $TOOL..."
     if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]src/tools/$TOOL$"; then
         echo "This PR updated 'src/tools/$TOOL', verifying if status is 'test-pass'..."
index dab385c09649cd5a4b54cff972b93b1b2ff8ab0f..02480c6937de16f419a8d2c764ef35c4681cc91d 100755 (executable)
@@ -46,6 +46,7 @@ export RUST_RELEASE_CHANNEL=nightly
 if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-thinlto"
 
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
index 194eb8d5f1753fb5f4501011cebdc1b585712474..a645960fe48946153936dd5628df4a90bd837981 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 194eb8d5f1753fb5f4501011cebdc1b585712474
+Subproject commit a645960fe48946153936dd5628df4a90bd837981
index 1d791b55b23ec5389fbd5b3cee80db3f8bbdd162..e6a5d5d10aa2fde0baed7b29bf672bd9f3af8962 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1d791b55b23ec5389fbd5b3cee80db3f8bbdd162
+Subproject commit e6a5d5d10aa2fde0baed7b29bf672bd9f3af8962
index 0137a052a62d868f02fcfded212f49fc0e634ba9..c51674186146be3bc1f076adf32f8bd4a8f1a717 100644 (file)
@@ -37,28 +37,23 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     p
 }
 
-#[lang = "exchange_free"]
-unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
-    libc::free(ptr as *mut libc::c_void)
-}
-
 #[lang = "box_free"]
 unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
-    deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
+    libc::free(ptr as *mut libc::c_void)
 }
 
 #[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
-    let x = box 1;
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _x = box 1;
 
     0
 }
 
 #[lang = "eh_personality"] extern fn rust_eh_personality() {}
 #[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
+#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
+#[no_mangle] pub extern fn rust_eh_register_frames () {}
+#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
 ```
 
 Note the use of `abort`: the `exchange_malloc` lang item is assumed to
@@ -80,7 +75,7 @@ Other features provided by lang items include:
 
 Lang items are loaded lazily by the compiler; e.g. if one never uses
 `Box` then there is no need to define functions for `exchange_malloc`
-and `exchange_free`. `rustc` will emit an error when an item is needed
+and `box_free`. `rustc` will emit an error when an item is needed
 but not found in the current crate or any that it depends on.
 
 Most lang items are defined by `libcore`, but if you're trying to build
@@ -318,4 +313,4 @@ the source code.
   - `phantom_data`: `libcore/marker.rs`
   - `freeze`: `libcore/marker.rs`
   - `debug_trait`: `libcore/fmt/mod.rs`
-  - `non_zero`: `libcore/nonzero.rs`
\ No newline at end of file
+  - `non_zero`: `libcore/nonzero.rs`
diff --git a/src/doc/unstable-book/src/language-features/match-beginning-vert.md b/src/doc/unstable-book/src/language-features/match-beginning-vert.md
deleted file mode 100644 (file)
index f0a51af..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# `match_beginning_vert`
-
-The tracking issue for this feature is [#44101].
-
-With this feature enabled, you are allowed to add a '|' to the beginning of a
-match arm:
-
-```rust
-#![feature(match_beginning_vert)]
-
-enum Foo { A, B, C }
-
-fn main() {
-    let x = Foo::A;
-    match x {
-        | Foo::A 
-        | Foo::B => println!("AB"),
-        | Foo::C => println!("C"),
-    }
-}
-```
-
-[#44101]: https://github.com/rust-lang/rust/issues/44101
\ No newline at end of file
diff --git a/src/doc/unstable-book/src/language-features/use-nested-groups.md b/src/doc/unstable-book/src/language-features/use-nested-groups.md
deleted file mode 100644 (file)
index 47b635b..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-# `use_nested_groups`
-
-The tracking issue for this feature is: [#44494]
-
-[#44494]: https://github.com/rust-lang/rust/issues/44494
-
-------------------------
-
-The `use_nested_groups` feature allows you to import multiple items from a
-complex module tree easily, by nesting different imports in the same
-declaration. For example:
-
-```rust
-#![feature(use_nested_groups)]
-# #![allow(unused_imports, dead_code)]
-#
-# mod foo {
-#     pub mod bar {
-#         pub type Foo = ();
-#     }
-#     pub mod baz {
-#         pub mod quux {
-#             pub type Bar = ();
-#         }
-#     }
-# }
-
-use foo::{
-    bar::{self, Foo},
-    baz::{*, quux::Bar},
-};
-#
-# fn main() {}
-```
-
-## Snippet for the book's new features appendix
-
-When stabilizing, add this to
-`src/doc/book/second-edition/src/appendix-07-newest-features.md`:
-
-### Nested groups in `use` declarations
-
-If you have a complex module tree with many different submodules and you need
-to import a few items from each one, it might be useful to group all the
-imports in the same declaration to keep your code clean and avoid repeating the
-base modules' name.
-
-The `use` declaration supports nesting to help you in those cases, both with
-simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
-all the items in `baz` and `Bar`:
-
-```rust
-# #![feature(use_nested_groups)]
-# #![allow(unused_imports, dead_code)]
-#
-# mod foo {
-#     pub mod bar {
-#         pub type Foo = ();
-#     }
-#     pub mod baz {
-#         pub mod quux {
-#             pub type Bar = ();
-#         }
-#     }
-# }
-#
-use foo::{
-    bar::{self, Foo},
-    baz::{*, quux::Bar},
-};
-#
-# fn main() {}
-```
-
-## Updated reference
-
-When stabilizing, replace the shortcut list in
-`src/doc/reference/src/items/use-declarations.md` with this updated one:
-
-* Simultaneously binding a list of paths with a common prefix, using the
-  glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};`
-* Simultaneously binding a list of paths with a common prefix and their common
-  parent module, using the `self` keyword, such as `use a::b::{self, c, d::e};`
-* Rebinding the target name as a new local name, using the syntax `use p::q::r
-  as x;`. This can also be used with the last two features:
-  `use a::b::{self as ab, c as abc}`.
-* Binding all paths matching a given prefix, using the asterisk wildcard syntax
-  `use a::b::*;`.
-* Nesting groups of the previous features multiple times, such as
-  `use a::b::{self as ab, c d::{*, e::f}};`
index d55083e0f8e03490aa23dea88ea1acfc810fe169..69647f37eecc6a8e98334bb13eb78d6fe06234ba 100644 (file)
@@ -28,14 +28,76 @@ let m = new WebAssembly.Module(buffer);
 
 let memory = null;
 
+function viewstruct(data, fields) {
+  return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
+}
+
 function copystr(a, b) {
-  if (memory === null) {
-    return null
-  }
-  let view = new Uint8Array(memory.buffer).slice(a, a + b);
+  let view = new Uint8Array(memory.buffer).subarray(a, a + b);
   return String.fromCharCode.apply(null, view);
 }
 
+function syscall_write([fd, ptr, len]) {
+  let s = copystr(ptr, len);
+  switch (fd) {
+    case 1: process.stdout.write(s); break;
+    case 2: process.stderr.write(s); break;
+  }
+}
+
+function syscall_exit([code]) {
+  process.exit(code);
+}
+
+function syscall_args(params) {
+  let [ptr, len] = params;
+
+  // Calculate total required buffer size
+  let totalLen = -1;
+  for (let i = 2; i < process.argv.length; ++i) {
+    totalLen += Buffer.byteLength(process.argv[i]) + 1;
+  }
+  if (totalLen < 0) { totalLen = 0; }
+  params[2] = totalLen;
+
+  // If buffer is large enough, copy data
+  if (len >= totalLen) {
+    let view = new Uint8Array(memory.buffer);
+    for (let i = 2; i < process.argv.length; ++i) {
+      let value = process.argv[i];
+      Buffer.from(value).copy(view, ptr);
+      ptr += Buffer.byteLength(process.argv[i]) + 1;
+    }
+  }
+}
+
+function syscall_getenv(params) {
+  let [keyPtr, keyLen, valuePtr, valueLen] = params;
+
+  let key = copystr(keyPtr, keyLen);
+  let value = process.env[key];
+
+  if (value == null) {
+    params[4] = 0xFFFFFFFF;
+  } else {
+    let view = new Uint8Array(memory.buffer);
+    let totalLen = Buffer.byteLength(value);
+    params[4] = totalLen;
+    if (valueLen >= totalLen) {
+      Buffer.from(value).copy(view, valuePtr);
+    }
+  }
+}
+
+function syscall_time(params) {
+  let t = Date.now();
+  let secs = Math.floor(t / 1000);
+  let millis = t % 1000;
+  params[1] = Math.floor(secs / 0x100000000);
+  params[2] = secs % 0x100000000;
+  params[3] = Math.floor(millis * 1000000);
+}
+
 let imports = {};
 imports.env = {
   // These are generated by LLVM itself for various intrinsic calls. Hopefully
@@ -48,68 +110,25 @@ imports.env = {
   log10: Math.log10,
   log10f: Math.log10,
 
-  // These are called in src/libstd/sys/wasm/stdio.rs and are used when
-  // debugging is enabled.
-  rust_wasm_write_stdout: function(a, b) {
-    let s = copystr(a, b);
-    if (s !== null) {
-      process.stdout.write(s);
-    }
-  },
-  rust_wasm_write_stderr: function(a, b) {
-    let s = copystr(a, b);
-    if (s !== null) {
-      process.stderr.write(s);
-    }
-  },
-
-  // These are called in src/libstd/sys/wasm/args.rs and are used when
-  // debugging is enabled.
-  rust_wasm_args_count: function() {
-    if (memory === null)
-      return 0;
-    return process.argv.length - 2;
-  },
-  rust_wasm_args_arg_size: function(i) {
-    return Buffer.byteLength(process.argv[i + 2]);
-  },
-  rust_wasm_args_arg_fill: function(idx, ptr) {
-    let arg = process.argv[idx + 2];
-    let view = new Uint8Array(memory.buffer);
-    Buffer.from(arg).copy(view, ptr);
-  },
-
-  // These are called in src/libstd/sys/wasm/os.rs and are used when
-  // debugging is enabled.
-  rust_wasm_getenv_len: function(a, b) {
-    let key = copystr(a, b);
-    if (key === null) {
-      return -1;
+  rust_wasm_syscall: function(index, data) {
+    switch (index) {
+      case 1: syscall_write(viewstruct(data, 3)); return true;
+      case 2: syscall_exit(viewstruct(data, 1)); return true;
+      case 3: syscall_args(viewstruct(data, 3)); return true;
+      case 4: syscall_getenv(viewstruct(data, 5)); return true;
+      case 6: syscall_time(viewstruct(data, 4)); return true;
+      default:
+        console.log("Unsupported syscall: " + index);
+        return false;
     }
-    if (!(key in process.env)) {
-      return -1;
-    }
-    return Buffer.byteLength(process.env[key]);
-  },
-  rust_wasm_getenv_data: function(a, b, ptr) {
-    let key = copystr(a, b);
-    let value = process.env[key];
-    let view = new Uint8Array(memory.buffer);
-    Buffer.from(value).copy(view, ptr);
-  },
-};
-
-let module_imports = WebAssembly.Module.imports(m);
-
-for (var i = 0; i < module_imports.length; i++) {
-  let imp = module_imports[i];
-  if (imp.module != 'env') {
-    continue
   }
-  if (imp.name == 'memory' && imp.kind == 'memory') {
-    memory = new WebAssembly.Memory({initial: 20});
-    imports.env.memory = memory;
-  }
-}
+};
 
 let instance = new WebAssembly.Instance(m, imports);
+memory = instance.exports.memory;
+try {
+  instance.exports.main();
+} catch (e) {
+  console.error(e);
+  process.exit(101);
+}
index 338e5c7fd95b47a07d7e780b3af976e6922830c5..566bfe2a3fb5e8c85c37a3f3714d097cebeaa8c7 100644 (file)
@@ -367,9 +367,36 @@ impl TypeId {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(stage0)]
     pub fn of<T: ?Sized + 'static>() -> TypeId {
         TypeId {
             t: unsafe { intrinsics::type_id::<T>() },
         }
     }
+
+    /// Returns the `TypeId` of the type this generic function has been
+    /// instantiated with.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::any::{Any, TypeId};
+    ///
+    /// fn is_string<T: ?Sized + Any>(_s: &T) -> bool {
+    ///     TypeId::of::<String>() == TypeId::of::<T>()
+    /// }
+    ///
+    /// fn main() {
+    ///     assert_eq!(is_string(&0), false);
+    ///     assert_eq!(is_string(&"cookie monster".to_string()), true);
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature="const_type_id")]
+    #[cfg(not(stage0))]
+    pub const fn of<T: ?Sized + 'static>() -> TypeId {
+        TypeId {
+            t: unsafe { intrinsics::type_id::<T>() },
+        }
+    }
 }
index e815d72d366466e79d3b3507c36585afeca5cb28..d3a83dc795c8577040b83b1c0e0440b826bf2880 100644 (file)
@@ -141,9 +141,9 @@ pub trait AsRef<T: ?Sized> {
 ///
 /// # Generic Implementations
 ///
-/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
-///   reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
-///   `&mut Foo` or `&&mut Foo`)
+/// - `AsMut` auto-dereferences if the inner type is a mutable reference
+///   (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo`
+///   or `&mut &mut Foo`)
 ///
 /// # Examples
 ///
index 6c8a1c3062b00633619ba56a7c7296ce8119d19d..8ad5a9861a02f07c586f3b9457d3f6f988f71c45 100644 (file)
@@ -530,9 +530,12 @@ fn fmt(&self, fmt: &mut Formatter) -> Result {
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
-                            defined in your crate, add `#[derive(Debug)]` or \
-                            manually implement it"]
+#[rustc_on_unimplemented(
+    on(crate_local, label="`{Self}` cannot be formatted using `:?`; \
+                            add `#[derive(Debug)]` or manually implement `{Debug}`"),
+    message="`{Self}` doesn't implement `{Debug}`",
+    label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`",
+)]
 #[lang = "debug_trait"]
 pub trait Debug {
     /// Formats the value using the given formatter.
@@ -593,9 +596,11 @@ pub trait Debug {
 ///
 /// println!("The origin is: {}", origin);
 /// ```
-#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
-                            formatter; try using `:?` instead if you are using \
-                            a format string"]
+#[rustc_on_unimplemented(
+    message="`{Self}` doesn't implement `{Display}`",
+    label="`{Self}` cannot be formatted with the default formatter; \
+           try using `:?` instead if you are using a format string",
+)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Display {
     /// Formats the value using the given formatter.
index a611dc02469e8abc68f2ff67c171b4d6f4ea8c59..a05d67a304fa02669a6cbc6cf3c09b291fd53b40 100644 (file)
     ///         ptr::copy_nonoverlapping(y, x, 1);
     ///         ptr::copy_nonoverlapping(&t, y, 1);
     ///
-    ///         // y and t now point to the same thing, but we need to completely forget `tmp`
+    ///         // y and t now point to the same thing, but we need to completely forget `t`
     ///         // because it's no longer relevant.
     ///         mem::forget(t);
     ///     }
index 35cd7441c66bcf4e0ef93706c54d4ada83a6b365..296fb8733ba6c858068f7675d1c2ed3fe9709804 100644 (file)
@@ -28,8 +28,13 @@ fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
 /// [module-level documentation]: index.html
 /// [impl]: index.html#implementing-iterator
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
-                            `.iter()` or a similar method"]
+#[rustc_on_unimplemented(
+    on(
+        _Self="&str",
+        label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
+    ),
+    label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method"
+)]
 #[doc(spotlight)]
 pub trait Iterator {
     /// The type of the elements being iterated over.
index 66a76a24df45afc983395776ad5c69f83c651d38..3b034efcce14ccbcc972b01090d564a32a630517 100644 (file)
@@ -10,7 +10,7 @@
 
 use convert::TryFrom;
 use mem;
-use ops::{self, Add, Sub};
+use ops::{self, Add, Sub, Try};
 use usize;
 
 use super::{FusedIterator, TrustedLen};
@@ -397,6 +397,28 @@ fn min(mut self) -> Option<A> {
     fn max(mut self) -> Option<A> {
         self.next_back()
     }
+
+    #[inline]
+    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    {
+        let mut accum = init;
+        if self.start <= self.end {
+            loop {
+                let (x, done) =
+                    if self.start < self.end {
+                        let n = self.start.add_one();
+                        (mem::replace(&mut self.start, n), false)
+                    } else {
+                        self.end.replace_zero();
+                        (self.start.replace_one(), true)
+                    };
+                accum = f(accum, x)?;
+                if done { break }
+            }
+        }
+        Try::from_ok(accum)
+    }
 }
 
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
@@ -418,6 +440,28 @@ fn next_back(&mut self) -> Option<A> {
             _ => None,
         }
     }
+
+    #[inline]
+    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    {
+        let mut accum = init;
+        if self.start <= self.end {
+            loop {
+                let (x, done) =
+                    if self.start < self.end {
+                        let n = self.end.sub_one();
+                        (mem::replace(&mut self.end, n), false)
+                    } else {
+                        self.start.replace_one();
+                        (self.end.replace_zero(), true)
+                    };
+                accum = f(accum, x)?;
+                if done { break }
+            }
+        }
+        Try::from_ok(accum)
+    }
 }
 
 #[unstable(feature = "fused", issue = "35602")]
index 2e1f925c49a36ba1fa1ca82f1b2e5be911235cfe..59a296c2a762c5e5a25ac3d3e1bcb55e11722502 100644 (file)
@@ -91,6 +91,7 @@
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(doc_spotlight)]
+#![feature(rustc_const_unstable)]
 
 #[prelude_import]
 #[allow(unused)]
index 93f6a0214d77d487b67edf144bce2d8875dc167a..21a0beccbf64d604e32dcfbfd86daa9da116197c 100644 (file)
@@ -189,6 +189,7 @@ pub fn forget<T>(t: T) {
 /// Type | size_of::\<Type>()
 /// ---- | ---------------
 /// () | 0
+/// bool | 1
 /// u8 | 1
 /// u16 | 2
 /// u32 | 4
index 207df84d080f2856d5407a15181443f288b9a8c6..3586fa5442fb44a1712882cbc8864570fa5ea04a 100644 (file)
@@ -239,7 +239,9 @@ fn powi(self, n: i32) -> f32 {
     /// Converts to degrees, assuming the number is in radians.
     #[inline]
     fn to_degrees(self) -> f32 {
-        self * (180.0f32 / consts::PI)
+        // Use a constant for better precision.
+        const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
+        self * PIS_IN_180
     }
 
     /// Converts to radians, assuming the number is in degrees.
index 9206132e8b46ff8be695108e516e5986a16cd6a0..64c0d508b388cf6b41b8a3df3e0567af55092822 100644 (file)
@@ -237,6 +237,9 @@ fn powi(self, n: i32) -> f64 {
     /// Converts to degrees, assuming the number is in radians.
     #[inline]
     fn to_degrees(self) -> f64 {
+        // The division here is correctly rounded with respect to the true
+        // value of 180/π. (This differs from f32, where a constant must be
+        // used to ensure a correctly rounded result.)
         self * (180.0f64 / consts::PI)
     }
 
index 8b3d662a6db774382bd9b14e7591ed55bffca87e..d0d0c09869e9dd398021ab70aa5be6cc1c54d948 100644 (file)
 /// ```
 #[lang = "add"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
+#[rustc_on_unimplemented(
+    on(
+        all(_Self="{integer}", RHS="{float}"),
+        message="cannot add a float to an integer",
+    ),
+    on(
+        all(_Self="{float}", RHS="{integer}"),
+        message="cannot add an integer to a float",
+    ),
+    message="cannot add `{RHS}` to `{Self}`",
+    label="no implementation for `{Self} + {RHS}`",
+)]
 pub trait Add<RHS=Self> {
     /// The resulting type after applying the `+` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -170,7 +181,8 @@ fn add(self, other: $t) -> $t { self + other }
 /// ```
 #[lang = "sub"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
+#[rustc_on_unimplemented(message="cannot substract `{RHS}` from `{Self}`",
+                         label="no implementation for `{Self} - {RHS}`")]
 pub trait Sub<RHS=Self> {
     /// The resulting type after applying the `-` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -287,7 +299,8 @@ fn sub(self, other: $t) -> $t { self - other }
 /// ```
 #[lang = "mul"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
+#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`",
+                         label="no implementation for `{Self} * {RHS}`")]
 pub trait Mul<RHS=Self> {
     /// The resulting type after applying the `*` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -408,7 +421,8 @@ fn mul(self, other: $t) -> $t { self * other }
 /// ```
 #[lang = "div"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
+#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`",
+                         label="no implementation for `{Self} / {RHS}`")]
 pub trait Div<RHS=Self> {
     /// The resulting type after applying the `/` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -490,7 +504,8 @@ fn div(self, other: $t) -> $t { self / other }
 /// ```
 #[lang = "rem"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
+#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`",
+                         label="no implementation for `{Self} % {RHS}`")]
 pub trait Rem<RHS=Self> {
     /// The resulting type after applying the `%` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -647,7 +662,8 @@ macro_rules! neg_impl_unsigned {
 /// ```
 #[lang = "add_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`",
+                         label="no implementation for `{Self} += {Rhs}`")]
 pub trait AddAssign<Rhs=Self> {
     /// Performs the `+=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -700,7 +716,8 @@ fn add_assign(&mut self, other: $t) { *self += other }
 /// ```
 #[lang = "sub_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot substract-assign `{Rhs}` from `{Self}`",
+                         label="no implementation for `{Self} -= {Rhs}`")]
 pub trait SubAssign<Rhs=Self> {
     /// Performs the `-=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -744,7 +761,8 @@ fn sub_assign(&mut self, other: $t) { *self -= other }
 /// ```
 #[lang = "mul_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`",
+                         label="no implementation for `{Self} *= {Rhs}`")]
 pub trait MulAssign<Rhs=Self> {
     /// Performs the `*=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -788,7 +806,8 @@ fn mul_assign(&mut self, other: $t) { *self *= other }
 /// ```
 #[lang = "div_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`",
+                         label="no implementation for `{Self} /= {Rhs}`")]
 pub trait DivAssign<Rhs=Self> {
     /// Performs the `/=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -835,7 +854,8 @@ fn div_assign(&mut self, other: $t) { *self /= other }
 /// ```
 #[lang = "rem_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``",
+                         label="no implementation for `{Self} %= {Rhs}`")]
 pub trait RemAssign<Rhs=Self> {
     /// Performs the `%=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
index 7ac5fc4debf1489150e9f1d4e151e1c60231edc0..a0ecd6cf75ce99277d279f4bc81aaccde0893045 100644 (file)
@@ -120,7 +120,8 @@ fn not(self) -> $t { !self }
 /// ```
 #[lang = "bitand"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`",
+                         label="no implementation for `{Self} & {RHS}`")]
 pub trait BitAnd<RHS=Self> {
     /// The resulting type after applying the `&` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -201,7 +202,8 @@ fn bitand(self, rhs: $t) -> $t { self & rhs }
 /// ```
 #[lang = "bitor"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`",
+                         label="no implementation for `{Self} | {RHS}`")]
 pub trait BitOr<RHS=Self> {
     /// The resulting type after applying the `|` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -285,7 +287,8 @@ fn bitor(self, rhs: $t) -> $t { self | rhs }
 /// ```
 #[lang = "bitxor"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`",
+                         label="no implementation for `{Self} ^ {RHS}`")]
 pub trait BitXor<RHS=Self> {
     /// The resulting type after applying the `^` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -365,7 +368,8 @@ fn bitxor(self, other: $t) -> $t { self ^ other }
 /// ```
 #[lang = "shl"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`",
+                         label="no implementation for `{Self} << {RHS}`")]
 pub trait Shl<RHS> {
     /// The resulting type after applying the `<<` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -466,7 +470,8 @@ macro_rules! shl_impl_all {
 /// ```
 #[lang = "shr"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`",
+                         label="no implementation for `{Self} >> {RHS}`")]
 pub trait Shr<RHS> {
     /// The resulting type after applying the `>>` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -579,7 +584,8 @@ macro_rules! shr_impl_all {
 /// ```
 #[lang = "bitand_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`",
+                         label="no implementation for `{Self} &= {Rhs}`")]
 pub trait BitAndAssign<Rhs=Self> {
     /// Performs the `&=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -626,7 +632,8 @@ fn bitand_assign(&mut self, other: $t) { *self &= other }
 /// ```
 #[lang = "bitor_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`",
+                         label="no implementation for `{Self} |= {Rhs}`")]
 pub trait BitOrAssign<Rhs=Self> {
     /// Performs the `|=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -673,7 +680,8 @@ fn bitor_assign(&mut self, other: $t) { *self |= other }
 /// ```
 #[lang = "bitxor_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`",
+                         label="no implementation for `{Self} ^= {Rhs}`")]
 pub trait BitXorAssign<Rhs=Self> {
     /// Performs the `^=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -718,7 +726,8 @@ fn bitxor_assign(&mut self, other: $t) { *self ^= other }
 /// ```
 #[lang = "shl_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`",
+                         label="no implementation for `{Self} <<= {Rhs}`")]
 pub trait ShlAssign<Rhs> {
     /// Performs the `<<=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -784,7 +793,8 @@ macro_rules! shl_assign_impl_all {
 /// ```
 #[lang = "shr_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`",
+                         label="no implementation for `{Self} >>= {Rhs}`")]
 pub trait ShrAssign<Rhs=Self> {
     /// Performs the `>>=` operation.
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
index fab5832d905df8262bfbaa85971ef913e8711844..3d84e910fe662d0de5873d267b8fbda362584038 100644 (file)
@@ -2461,7 +2461,7 @@ fn from(p: NonNull<T>) -> Self {
 }
 
 /// Previous name of `NonNull`.
-#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")]
+#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")]
 #[unstable(feature = "shared", issue = "27730")]
 pub type Shared<T> = NonNull<T>;
 
@@ -2482,26 +2482,19 @@ fn from(p: NonNull<T>) -> Self {
 /// Usually this won't be necessary; covariance is correct for most safe abstractions,
 /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they
 /// provide a public API that follows the normal shared XOR mutable rules of Rust.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 pub struct NonNull<T: ?Sized> {
     pointer: NonZero<*const T>,
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
-impl<T: ?Sized> fmt::Debug for NonNull<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Pointer::fmt(&self.as_ptr(), f)
-    }
-}
-
 /// `NonNull` pointers are not `Send` because the data they reference may be aliased.
 // NB: This impl is unnecessary, but should provide better error messages.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> !Send for NonNull<T> { }
 
 /// `NonNull` pointers are not `Sync` because the data they reference may be aliased.
 // NB: This impl is unnecessary, but should provide better error messages.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> !Sync for NonNull<T> { }
 
 impl<T: Sized> NonNull<T> {
@@ -2509,7 +2502,7 @@ impl<T: Sized> NonNull<T> {
     ///
     /// This is useful for initializing types which lazily allocate, like
     /// `Vec::new` does.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub fn dangling() -> Self {
         unsafe {
             let ptr = mem::align_of::<T>() as *mut T;
@@ -2524,19 +2517,19 @@ impl<T: ?Sized> NonNull<T> {
     /// # Safety
     ///
     /// `ptr` must be non-null.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
         NonNull { pointer: NonZero::new_unchecked(ptr) }
     }
 
     /// Creates a new `NonNull` if `ptr` is non-null.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub fn new(ptr: *mut T) -> Option<Self> {
         NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz })
     }
 
     /// Acquires the underlying `*mut` pointer.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub fn as_ptr(self) -> *mut T {
         self.pointer.get() as *mut T
     }
@@ -2546,7 +2539,7 @@ pub fn as_ptr(self) -> *mut T {
     /// The resulting lifetime is bound to self so this behaves "as if"
     /// it were actually an instance of T that is getting borrowed. If a longer
     /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub unsafe fn as_ref(&self) -> &T {
         &*self.as_ptr()
     }
@@ -2556,47 +2549,93 @@ pub unsafe fn as_ref(&self) -> &T {
     /// The resulting lifetime is bound to self so this behaves "as if"
     /// it were actually an instance of T that is getting borrowed. If a longer
     /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
-    #[stable(feature = "nonnull", since = "1.24.0")]
+    #[stable(feature = "nonnull", since = "1.25.0")]
     pub unsafe fn as_mut(&mut self) -> &mut T {
         &mut *self.as_ptr()
     }
+
+    /// Cast to a pointer of another type
+    #[unstable(feature = "nonnull_cast", issue = "47653")]
+    pub fn cast<U>(self) -> NonNull<U> {
+        unsafe {
+            NonNull::new_unchecked(self.as_ptr() as *mut U)
+        }
+    }
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> Clone for NonNull<T> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> Copy for NonNull<T> { }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> fmt::Debug for NonNull<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Pointer::fmt(&self.as_ptr(), f)
+    }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> fmt::Pointer for NonNull<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Pointer::fmt(&self.as_ptr(), f)
     }
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> Eq for NonNull<T> {}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> PartialEq for NonNull<T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.as_ptr() == other.as_ptr()
+    }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> Ord for NonNull<T> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.as_ptr().cmp(&other.as_ptr())
+    }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> PartialOrd for NonNull<T> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.as_ptr().partial_cmp(&other.as_ptr())
+    }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> hash::Hash for NonNull<T> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.as_ptr().hash(state)
+    }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
     fn from(unique: Unique<T>) -> Self {
         NonNull { pointer: unique.pointer }
     }
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
     fn from(reference: &'a mut T) -> Self {
         NonNull { pointer: NonZero::from(reference) }
     }
 }
 
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
     fn from(reference: &'a T) -> Self {
         NonNull { pointer: NonZero::from(reference) }
index e52e119ff59b954389dbd2ec87266f57e22c9b09..dc866d180bfa0c122db5b96789a010895a47cc18 100644 (file)
@@ -1459,6 +1459,26 @@ fn test_range_inclusive_min() {
     assert_eq!(r.min(), None);
 }
 
+#[test]
+fn test_range_inclusive_folds() {
+    assert_eq!((1..=10).sum::<i32>(), 55);
+    assert_eq!((1..=10).rev().sum::<i32>(), 55);
+
+    let mut it = 40..=50;
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it, 44..=50);
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it, 44..=47);
+
+    let mut it = 10..=20;
+    assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165));
+    assert_eq!(it, 1..=0);
+
+    let mut it = 10..=20;
+    assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165));
+    assert_eq!(it, 1..=0);
+}
+
 #[test]
 fn test_repeat() {
     let mut it = repeat(42);
index b9e816baac0dc0f50f8e340eff4908b3e58ba57d..6768e0ade43049387510f6dd65716b06917afa95 100644 (file)
@@ -685,7 +685,7 @@ fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
                 })
             }
 
-            DotEq => unreachable!(),
+            DotEq => joint!('.', Eq),
             OpenDelim(..) | CloseDelim(..) => unreachable!(),
             Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
         };
index 8bd89b834d6b6ce3d03da35280edb5530bc0f186..4c256556191fa58f3577ef2903b976f27b291d75 100644 (file)
@@ -256,6 +256,28 @@ trait Foo {
 }
 ```
 
+### The trait cannot contain associated constants
+
+Just like static functions, associated constants aren't stored on the method
+table. If the trait or any subtrait contain an associated constant, they cannot
+be made into an object.
+
+```compile_fail,E0038
+trait Foo {
+    const X: i32;
+}
+
+impl Foo {}
+```
+
+A simple workaround is to use a helper method instead:
+
+```
+trait Foo {
+    fn x(&self) -> i32;
+}
+```
+
 ### The trait cannot use `Self` as a type parameter in the supertrait listing
 
 This is similar to the second sub-error, but subtler. It happens in situations
index b10e742595720dc595863c124d1404ce9d74f8b8..03fc40b2e39fcb79fe374ecd17bfcaa42861f07a 100644 (file)
@@ -175,25 +175,6 @@ fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             ty::ReEarlyBound(_) |
             ty::ReFree(_) => {
                 let scope = region.free_region_binding_scope(self);
-                let prefix = match *region {
-                    ty::ReEarlyBound(ref br) => {
-                        format!("the lifetime {} as defined on", br.name)
-                    }
-                    ty::ReFree(ref fr) => {
-                        match fr.bound_region {
-                            ty::BrAnon(idx) => {
-                                format!("the anonymous lifetime #{} defined on", idx + 1)
-                            }
-                            ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
-                            _ => {
-                                format!("the lifetime {} as defined on",
-                                        fr.bound_region)
-                            }
-                        }
-                    }
-                    _ => bug!()
-                };
-
                 let node = self.hir.as_local_node_id(scope)
                                    .unwrap_or(DUMMY_NODE_ID);
                 let unknown;
@@ -218,7 +199,26 @@ fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         &unknown
                     }
                 };
-                let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
+                let (prefix, span) = match *region {
+                    ty::ReEarlyBound(ref br) => {
+                        (format!("the lifetime {} as defined on", br.name),
+                         self.sess.codemap().def_span(self.hir.span(node)))
+                    }
+                    ty::ReFree(ref fr) => {
+                        match fr.bound_region {
+                            ty::BrAnon(idx) => {
+                                (format!("the anonymous lifetime #{} defined on", idx + 1),
+                                 self.hir.span(node))
+                            }
+                            ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
+                                               self.hir.span(node)),
+                            _ => (format!("the lifetime {} as defined on", fr.bound_region),
+                                  self.sess.codemap().def_span(self.hir.span(node))),
+                        }
+                    }
+                    _ => bug!()
+                };
+                let (msg, opt_span) = explain_span(self, tag, span);
                 (format!("{} {}", prefix, msg), opt_span)
             }
 
@@ -807,7 +807,7 @@ pub fn note_type_err(&self,
             }
         };
 
-        let span = cause.span;
+        let span = cause.span(&self.tcx);
 
         diag.span_label(span, terr.to_string());
         if let Some((sp, msg)) = secondary_span {
@@ -842,7 +842,7 @@ pub fn note_type_err(&self,
                                     "did you mean `{}(/* fields */)`?",
                                     self.tcx.item_path_str(def_id)
                                 );
-                                diag.span_label(cause.span, message);
+                                diag.span_label(span, message);
                             }
                         }
                     }
@@ -870,7 +870,7 @@ pub fn report_and_explain_type_error(&self,
                trace,
                terr);
 
-        let span = trace.cause.span;
+        let span = trace.cause.span(&self.tcx);
         let failure_code = trace.cause.as_failure_code(terr);
         let mut diag = match failure_code {
             FailureCode::Error0317(failure_str) => {
@@ -1076,6 +1076,31 @@ fn report_sub_sup_conflict(&self,
             sup_region,
             "...");
 
+        match (&sup_origin, &sub_origin) {
+            (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
+                if let (Some((sup_expected, sup_found)),
+                        Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
+                                                            self.values_str(&sub_trace.values)) {
+                    if sub_expected == sup_expected && sub_found == sup_found {
+                        self.tcx.note_and_explain_region(
+                            region_scope_tree,
+                            &mut err,
+                            "...but the lifetime must also be valid for ",
+                            sub_region,
+                            "...",
+                        );
+                        err.note(&format!("...so that the {}:\nexpected {}\n   found {}",
+                                          sup_trace.cause.as_requirement_str(),
+                                          sup_expected.content(),
+                                          sup_found.content()));
+                        err.emit();
+                        return;
+                    }
+                }
+            }
+            _ => {}
+        }
+
         self.note_region_origin(&mut err, &sup_origin);
 
         self.tcx.note_and_explain_region(region_scope_tree, &mut err,
index e46613b3e4da0cd0fa804878c50ae8d1c12193fc..02ec9fe74c1fe693bf5c24e60da393c93c170266 100644 (file)
@@ -23,12 +23,10 @@ pub(super) fn note_region_origin(&self,
                 if let Some((expected, found)) = self.values_str(&trace.values) {
                     let expected = expected.content();
                     let found = found.content();
-                    // FIXME: do we want a "the" here?
-                    err.span_note(trace.cause.span,
-                                  &format!("...so that {} (expected {}, found {})",
-                                           trace.cause.as_requirement_str(),
-                                           expected,
-                                           found));
+                    err.note(&format!("...so that the {}:\nexpected {}\n   found {}",
+                                      trace.cause.as_requirement_str(),
+                                      expected,
+                                      found));
                 } else {
                     // FIXME: this really should be handled at some earlier stage. Our
                     // handling of region checking when type errors are present is
index d727dfb0c4b2deef220d33c0f16cefa057ad8e37..db6863d6dadc272a0d01fc86296d6c92d4ec38ea 100644 (file)
@@ -66,6 +66,7 @@
 #![feature(specialization)]
 #![feature(unboxed_closures)]
 #![feature(underscore_lifetimes)]
+#![feature(universal_impl_trait)]
 #![feature(trace_macros)]
 #![feature(catch_expr)]
 #![feature(test)]
index 143d2c2ea28bba8361cdf48539715bb418d45d39..0577800f3f4113f92e9534a3a4b5d991126af718 100644 (file)
     "raw pointer to an inference variable"
 }
 
+declare_lint! {
+    pub ELIDED_LIFETIME_IN_PATH,
+    Allow,
+    "hidden lifetime parameters are deprecated, try `Foo<'_>`"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -291,7 +297,9 @@ fn get_lints(&self) -> LintArray {
             UNUSED_MUT,
             COERCE_NEVER,
             SINGLE_USE_LIFETIME,
-            TYVAR_BEHIND_RAW_POINTER
+            TYVAR_BEHIND_RAW_POINTER,
+            ELIDED_LIFETIME_IN_PATH
+
         )
     }
 }
index 5336c1944e8c4d905f66c5928574b5c832cbeafd..ed937046e5ed747b6ece8e486bcfbc250e79140e 100644 (file)
@@ -631,7 +631,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a LateContext<'a, 'tcx> {
     type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        (self.tcx, self.param_env.reveal_all()).layout_of(ty)
+        self.tcx.layout_of(self.param_env.and(ty))
     }
 }
 
@@ -1042,11 +1042,20 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
     // Put the lint store levels and passes back in the session.
     cx.lint_sess.restore(&sess.lint_store);
 
-    // Emit all buffered lints from early on in the session now that we've
-    // calculated the lint levels for all AST nodes.
-    for (_id, lints) in cx.buffered.map {
-        for early_lint in lints {
-            span_bug!(early_lint.span, "failed to process buffered lint here");
+    // All of the buffered lints should have been emitted at this point.
+    // If not, that means that we somehow buffered a lint for a node id
+    // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
+    //
+    // Rustdoc runs everybody-loops before the early lints and removes
+    // function bodies, so it's totally possible for linted
+    // node ids to not exist (e.g. macros defined within functions for the
+    // unused_macro lint) anymore. So we only run this check
+    // when we're not in rustdoc mode. (see issue #47639)
+    if !sess.opts.actually_rustdoc {
+        for (_id, lints) in cx.buffered.map {
+            for early_lint in lints {
+                span_bug!(early_lint.span, "failed to process buffered lint here");
+            }
         }
     }
 }
index dad2d7a7c90fb4ffd33668b8b9844de3cd9cefa9..e5619f469e774bd22b8c6af6cf981bc4eec9d863 100644 (file)
@@ -467,9 +467,13 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     fn visit_pat(&mut self, pat: &'tcx Pat) {
+        intravisit::walk_pat(self, pat);
+
         self.expr_and_pat_count += 1;
 
-        intravisit::walk_pat(self, pat);
+        if pat.id == self.id {
+            self.result = Some(self.expr_and_pat_count);
+        }
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
@@ -814,7 +818,8 @@ pub fn free_scope<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeReg
 
     /// Checks whether the given scope contains a `yield`. If so,
     /// returns `Some((span, expr_count))` with the span of a yield we found and
-    /// the number of expressions appearing before the `yield` in the body.
+    /// the number of expressions and patterns appearing before the `yield` in the body + 1.
+    /// If there a are multiple yields in a scope, the one with the highest number is returned.
     pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
         self.yield_in_scope.get(&scope).cloned()
     }
index 944d770516375ea20dd03aad6cd987722f7f3c8f..59460141166b113585fd203453f2269035fd6df0 100644 (file)
@@ -737,7 +737,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         if lifetime_ref.is_elided() {
-            self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref));
+            self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false);
             return;
         }
         if lifetime_ref.is_static() {
@@ -1444,7 +1444,7 @@ fn visit_segment_parameters(
         }
 
         if params.lifetimes.iter().all(|l| l.is_elided()) {
-            self.resolve_elided_lifetimes(&params.lifetimes);
+            self.resolve_elided_lifetimes(&params.lifetimes, true);
         } else {
             for l in &params.lifetimes {
                 self.visit_lifetime(l);
@@ -1803,14 +1803,24 @@ fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
         }
     }
 
-    fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime]) {
+    fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) {
         if lifetime_refs.is_empty() {
             return;
         }
 
         let span = lifetime_refs[0].span;
+        let id = lifetime_refs[0].id;
         let mut late_depth = 0;
         let mut scope = self.scope;
+        if deprecated {
+            self.tcx
+                .struct_span_lint_node(
+                    lint::builtin::ELIDED_LIFETIME_IN_PATH,
+                    id,
+                    span,
+                    &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
+                .emit();
+        }
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
index 3b644aa13f321cc8e9183f3490b56432480f885d..d82691f882c7348b7ad2e1cc01cc13963c1eb945 100644 (file)
@@ -1515,8 +1515,8 @@ pub enum AggregateKind<'tcx> {
     Array(Ty<'tcx>),
     Tuple,
 
-    /// The second field is variant number (discriminant), it's equal
-    /// to 0 for struct and union expressions. The fourth field is
+    /// The second field is the variant index. It's equal to 0 for struct
+    /// and union expressions. The fourth field is
     /// active field number and is present only for union expressions
     /// -- e.g. for a union expression `SomeUnion { c: .. }`, the
     /// active field index would identity the field `c`
@@ -1825,7 +1825,7 @@ pub struct Location {
     /// the location is within this block
     pub block: BasicBlock,
 
-    /// the location is the start of the this statement; or, if `statement_index`
+    /// the location is the start of the statement; or, if `statement_index`
     /// == num-statements, then the start of the terminator.
     pub statement_index: usize,
 }
index b9546143a054b32af67f2b88bf2ddd72cf5edfe5..c56575f432d1e7c705090f92dd3ab0cfb695346d 100644 (file)
@@ -548,25 +548,6 @@ pub fn with_extension(&self, extension: &str) -> PathBuf {
     pub fn filestem(&self) -> String {
         format!("{}{}", self.out_filestem, self.extra)
     }
-
-    pub fn contains_path(&self, input_path: &PathBuf) -> bool {
-        let input_path = input_path.canonicalize().ok();
-        if input_path.is_none() {
-            return false
-        }
-        match self.single_output_file {
-            Some(ref output_path) => output_path.canonicalize().ok() == input_path,
-            None => {
-                for k in self.outputs.keys() {
-                    let output_path = self.path(k.to_owned());
-                    if output_path.canonicalize().ok() == input_path {
-                        return true;
-                    }
-                }
-                false
-            }
-        }
-    }
 }
 
 pub fn host_triple() -> &'static str {
@@ -1288,6 +1269,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
          themselves"),
+    approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
+        "include machine-applicability of suggestions in JSON output"),
     unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
         "Present the input source, unstable (and less-pretty) variants;
         valid types are any of the types for `--pretty`, as well as:
index b526819e3ce70f5bc00943634e7528f7d751da1f..f4a00a43d8d92b5dcb471e5bb1c3e973906bab0b 100644 (file)
@@ -913,10 +913,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
             Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false))
         }
         (config::ErrorOutputType::Json(pretty), None) => {
-            Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
+            Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
+                     pretty, sopts.debugging_opts.approximate_suggestions))
         }
         (config::ErrorOutputType::Json(pretty), Some(dst)) => {
-            Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
+            Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
+                     pretty, sopts.debugging_opts.approximate_suggestions))
         }
         (config::ErrorOutputType::Short(color_config), None) => {
             Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false))
index ae68e3fe8d01f065c2954ff6465fcccceecca21b..9de18612d816c468db047ff0bab636e344c9f690 100644 (file)
@@ -19,7 +19,7 @@
 use ty::fold::TypeFoldable;
 use ty::subst::Subst;
 
-use infer::{InferCtxt, InferOk};
+use infer::{InferOk};
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -40,13 +40,20 @@ pub struct OverlapResult<'tcx> {
     pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
 }
 
-/// If there are types that satisfy both impls, returns a suitably-freshened
-/// `ImplHeader` with those types substituted
-pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
-                                          impl1_def_id: DefId,
-                                          impl2_def_id: DefId,
-                                          intercrate_mode: IntercrateMode)
-                                          -> Option<OverlapResult<'tcx>>
+/// If there are types that satisfy both impls, invokes `on_overlap`
+/// with a suitably-freshened `ImplHeader` with those types
+/// substituted. Otherwise, invokes `no_overlap`.
+pub fn overlapping_impls<'gcx, F1, F2, R>(
+    tcx: TyCtxt<'_, 'gcx, 'gcx>,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
+    intercrate_mode: IntercrateMode,
+    on_overlap: F1,
+    no_overlap: F2,
+) -> R
+where
+    F1: FnOnce(OverlapResult<'_>) -> R,
+    F2: FnOnce() -> R,
 {
     debug!("impl_can_satisfy(\
            impl1_def_id={:?}, \
@@ -56,8 +63,23 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
            impl2_def_id,
            intercrate_mode);
 
-    let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
-    overlap(selcx, impl1_def_id, impl2_def_id)
+    let overlaps = tcx.infer_ctxt().enter(|infcx| {
+        let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+        overlap(selcx, impl1_def_id, impl2_def_id).is_some()
+    });
+
+    if !overlaps {
+        return no_overlap();
+    }
+
+    // In the case where we detect an error, run the check again, but
+    // this time tracking intercrate ambuiguity causes for better
+    // diagnostics. (These take time and can lead to false errors.)
+    tcx.infer_ctxt().enter(|infcx| {
+        let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+        selcx.enable_tracking_intercrate_ambiguity_causes();
+        on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
+    })
 }
 
 fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
@@ -135,10 +157,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
         return None
     }
 
-    Some(OverlapResult {
-        impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
-        intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
-    })
+    let impl_header =  selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
+    let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+    debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+    Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
 }
 
 pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
index d65becb912a3cc57150e8a44c4014baf03ba6265..d4bcf00be80896ad23fd7d327e92ab984984a9ea 100644 (file)
@@ -348,7 +348,7 @@ fn on_unimplemented_note(
         if direct {
             // this is a "direct", user-specified, rather than derived,
             // obligation.
-            flags.push(("direct", None));
+            flags.push(("direct".to_string(), None));
         }
 
         if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
@@ -359,21 +359,37 @@ fn on_unimplemented_note(
             // Currently I'm leaving it for what I need for `try`.
             if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
                 method = self.tcx.item_name(item);
-                flags.push(("from_method", None));
-                flags.push(("from_method", Some(&*method)));
+                flags.push(("from_method".to_string(), None));
+                flags.push(("from_method".to_string(), Some(method.to_string())));
             }
         }
 
         if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
             desugaring = k.as_symbol().as_str();
-            flags.push(("from_desugaring", None));
-            flags.push(("from_desugaring", Some(&*desugaring)));
+            flags.push(("from_desugaring".to_string(), None));
+            flags.push(("from_desugaring".to_string(), Some(desugaring.to_string())));
+        }
+        let generics = self.tcx.generics_of(def_id);
+        let self_ty = trait_ref.self_ty();
+        let self_ty_str = self_ty.to_string();
+        flags.push(("_Self".to_string(), Some(self_ty_str.clone())));
+
+        for param in generics.types.iter() {
+            let name = param.name.as_str().to_string();
+            let ty = trait_ref.substs.type_for_def(param);
+            let ty_str = ty.to_string();
+            flags.push((name.clone(),
+                        Some(ty_str.clone())));
+        }
+
+        if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) {
+            flags.push(("crate_local".to_string(), None));
         }
 
         if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
             self.tcx, trait_ref.def_id, def_id
         ) {
-            command.evaluate(self.tcx, trait_ref, &flags)
+            command.evaluate(self.tcx, trait_ref, &flags[..])
         } else {
             OnUnimplementedNote::empty()
         }
@@ -549,7 +565,7 @@ pub fn report_selection_error(&self,
                                 .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
                             .unwrap_or((String::new(), String::new()));
 
-                        let OnUnimplementedNote { message, label }
+                        let OnUnimplementedNote { message, label, note }
                             = self.on_unimplemented_note(trait_ref, obligation);
                         let have_alt_message = message.is_some() || label.is_some();
 
@@ -578,6 +594,10 @@ pub fn report_selection_error(&self,
                                                      trait_ref,
                                                      trait_ref.self_ty()));
                         }
+                        if let Some(ref s) = note {
+                            // If it has a custom "#[rustc_on_unimplemented]" note, let's display it
+                            err.note(s.as_str());
+                        }
 
                         self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
 
@@ -1266,6 +1286,10 @@ fn note_obligation_cause_code<T>(&self,
                 err.note("the return type of a function must have a \
                           statically known size");
             }
+            ObligationCauseCode::SizedYieldType => {
+                err.note("the yield type of a generator must have a \
+                          statically known size");
+            }
             ObligationCauseCode::AssignmentLhsSized => {
                 err.note("the left-hand-side of an assignment must have a statically known size");
             }
index fd47e09aad7f9119270981d8af3d3eb6f2d97b1d..80819a86b7c4655f8a3a41b0baacb29f4a37d1de 100644 (file)
@@ -100,6 +100,19 @@ pub struct ObligationCause<'tcx> {
     pub code: ObligationCauseCode<'tcx>
 }
 
+impl<'tcx> ObligationCause<'tcx> {
+    pub fn span<'a, 'gcx>(&self, tcx: &TyCtxt<'a, 'gcx, 'tcx>) -> Span {
+        match self.code {
+            ObligationCauseCode::CompareImplMethodObligation { .. } |
+            ObligationCauseCode::MainFunctionType |
+            ObligationCauseCode::StartFunctionType => {
+                tcx.sess.codemap().def_span(self.span)
+            }
+            _ => self.span,
+        }
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
@@ -138,6 +151,8 @@ pub enum ObligationCauseCode<'tcx> {
     VariableType(ast::NodeId),
     /// Return type must be Sized
     SizedReturnType,
+    /// Yield type must be Sized
+    SizedYieldType,
     /// [T,..n] --> T must be Copy
     RepeatVec,
 
index 757b078086d9c0531a0b342c3502c386e17c4854..8c2c1cfa454729c5cbfcf1593dde5771617b4efa 100644 (file)
@@ -29,16 +29,18 @@ pub struct OnUnimplementedDirective {
     pub subcommands: Vec<OnUnimplementedDirective>,
     pub message: Option<OnUnimplementedFormatString>,
     pub label: Option<OnUnimplementedFormatString>,
+    pub note: Option<OnUnimplementedFormatString>,
 }
 
 pub struct OnUnimplementedNote {
     pub message: Option<String>,
     pub label: Option<String>,
+    pub note: Option<String>,
 }
 
 impl OnUnimplementedNote {
     pub fn empty() -> Self {
-        OnUnimplementedNote { message: None, label: None }
+        OnUnimplementedNote { message: None, label: None, note: None }
     }
 }
 
@@ -89,6 +91,7 @@ pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
         let mut message = None;
         let mut label = None;
+        let mut note = None;
         let mut subcommands = vec![];
         for item in item_iter {
             if item.check_name("message") && message.is_none() {
@@ -103,8 +106,14 @@ pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         tcx, trait_def_id, label_.as_str(), span)?);
                     continue;
                 }
+            } else if item.check_name("note") && note.is_none() {
+                if let Some(note_) = item.value_str() {
+                    note = Some(OnUnimplementedFormatString::try_parse(
+                        tcx, trait_def_id, note_.as_str(), span)?);
+                    continue;
+                }
             } else if item.check_name("on") && is_root &&
-                message.is_none() && label.is_none()
+                message.is_none() && label.is_none() && note.is_none()
             {
                 if let Some(items) = item.meta_item_list() {
                     if let Ok(subcommand) =
@@ -128,7 +137,7 @@ pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         if errored {
             Err(ErrorReported)
         } else {
-            Ok(OnUnimplementedDirective { condition, message, label, subcommands })
+            Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
         }
     }
 
@@ -154,7 +163,8 @@ pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                 message: None,
                 subcommands: vec![],
                 label: Some(OnUnimplementedFormatString::try_parse(
-                    tcx, trait_def_id, value.as_str(), attr.span)?)
+                    tcx, trait_def_id, value.as_str(), attr.span)?),
+                note: None,
             }))
         } else {
             return Err(parse_error(tcx, attr.span,
@@ -169,20 +179,20 @@ pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub fn evaluate(&self,
                     tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     trait_ref: ty::TraitRef<'tcx>,
-                    options: &[(&str, Option<&str>)])
+                    options: &[(String, Option<String>)])
                     -> OnUnimplementedNote
     {
         let mut message = None;
         let mut label = None;
-        info!("evaluate({:?}, trait_ref={:?}, options={:?})",
-              self, trait_ref, options);
+        let mut note = None;
+        info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition {
                 if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
-                    options.contains(&(&c.name().as_str(),
-                                      match c.value_str().map(|s| s.as_str()) {
-                                          Some(ref s) => Some(s),
+                    options.contains(&(c.name().as_str().to_string(),
+                                      match c.value_str().map(|s| s.as_str().to_string()) {
+                                          Some(s) => Some(s),
                                           None => None
                                       }))
                 }) {
@@ -198,11 +208,16 @@ pub fn evaluate(&self,
             if let Some(ref label_) = command.label {
                 label = Some(label_.clone());
             }
+
+            if let Some(ref note_) = command.note {
+                note = Some(note_.clone());
+            }
         }
 
         OnUnimplementedNote {
             label: label.map(|l| l.format(tcx, trait_ref)),
-            message: message.map(|m| m.format(tcx, trait_ref))
+            message: message.map(|m| m.format(tcx, trait_ref)),
+            note: note.map(|n| n.format(tcx, trait_ref)),
         }
     }
 }
index 55cbc890e1e91de2c39b45c9975ccb686fee9305..4ed25646d436d03671852d1d3a0fcd0f625e9c85 100644 (file)
@@ -92,10 +92,10 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
 
     inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
 
-    intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+    intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum IntercrateAmbiguityCause {
     DownstreamCrate {
         trait_desc: String,
@@ -423,7 +423,7 @@ pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx
             freshener: infcx.freshener(),
             intercrate: None,
             inferred_obligations: SnapshotVec::new(),
-            intercrate_ambiguity_causes: Vec::new(),
+            intercrate_ambiguity_causes: None,
         }
     }
 
@@ -435,10 +435,30 @@ pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
             freshener: infcx.freshener(),
             intercrate: Some(mode),
             inferred_obligations: SnapshotVec::new(),
-            intercrate_ambiguity_causes: Vec::new(),
+            intercrate_ambiguity_causes: None,
         }
     }
 
+    /// Enables tracking of intercrate ambiguity causes. These are
+    /// used in coherence to give improved diagnostics. We don't do
+    /// this until we detect a coherence error because it can lead to
+    /// false overflow results (#47139) and because it costs
+    /// computation time.
+    pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+        assert!(self.intercrate.is_some());
+        assert!(self.intercrate_ambiguity_causes.is_none());
+        self.intercrate_ambiguity_causes = Some(vec![]);
+        debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+    }
+
+    /// Gets the intercrate ambiguity causes collected since tracking
+    /// was enabled and disables tracking at the same time. If
+    /// tracking is not enabled, just returns an empty vector.
+    pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+        assert!(self.intercrate.is_some());
+        self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+    }
+
     pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
@@ -451,10 +471,6 @@ pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
 
-    pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
-        &self.intercrate_ambiguity_causes
-    }
-
     /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
     /// context's self.
     fn in_snapshot<R, F>(&mut self, f: F) -> R
@@ -828,19 +844,23 @@ fn evaluate_stack<'o>(&mut self,
             debug!("evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
                    stack.fresh_trait_ref);
             // Heuristics: show the diagnostics when there are no candidates in crate.
-            if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
-                    let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                    let self_ty = trait_ref.self_ty();
-                    let cause = IntercrateAmbiguityCause::DownstreamCrate {
-                        trait_desc: trait_ref.to_string(),
-                        self_desc: if self_ty.has_concrete_skeleton() {
-                            Some(self_ty.to_string())
-                        } else {
-                            None
-                        },
-                    };
-                    self.intercrate_ambiguity_causes.push(cause);
+            if self.intercrate_ambiguity_causes.is_some() {
+                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                    if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let cause = IntercrateAmbiguityCause::DownstreamCrate {
+                            trait_desc: trait_ref.to_string(),
+                            self_desc: if self_ty.has_concrete_skeleton() {
+                                Some(self_ty.to_string())
+                            } else {
+                                None
+                            },
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
                 }
             }
             return EvaluatedToAmbig;
@@ -1092,25 +1112,29 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
             None => {}
             Some(conflict) => {
                 debug!("coherence stage: not knowable");
-                // Heuristics: show the diagnostics when there are no candidates in crate.
-                let candidate_set = self.assemble_candidates(stack)?;
-                if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
-                    !self.evaluate_candidate(stack, &c).may_apply()
-                }) {
-                    let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                    let self_ty = trait_ref.self_ty();
-                    let trait_desc = trait_ref.to_string();
-                    let self_desc = if self_ty.has_concrete_skeleton() {
-                        Some(self_ty.to_string())
-                    } else {
-                        None
-                    };
-                    let cause = if let Conflict::Upstream = conflict {
-                        IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
-                    } else {
-                        IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
-                    };
-                    self.intercrate_ambiguity_causes.push(cause);
+                if self.intercrate_ambiguity_causes.is_some() {
+                    debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                    // Heuristics: show the diagnostics when there are no candidates in crate.
+                    let candidate_set = self.assemble_candidates(stack)?;
+                    if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
+                        !self.evaluate_candidate(stack, &c).may_apply()
+                    }) {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let trait_desc = trait_ref.to_string();
+                        let self_desc = if self_ty.has_concrete_skeleton() {
+                            Some(self_ty.to_string())
+                        } else {
+                            None
+                        };
+                        let cause = if let Conflict::Upstream = conflict {
+                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+                        } else {
+                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
                 }
                 return Ok(None);
             }
index 834389e5d009c62145d41e7fd88b2d0698e62265..a10169e13e60a705e4bc9e0bc3d6cf75cf5a4a75 100644 (file)
@@ -133,12 +133,12 @@ fn insert(&mut self,
             };
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
-                let overlap = traits::overlapping_impls(&infcx,
-                                                        possible_sibling,
-                                                        impl_def_id,
-                                                        traits::IntercrateMode::Issue43355);
-                if let Some(overlap) = overlap {
+            let (le, ge) = traits::overlapping_impls(
+                tcx,
+                possible_sibling,
+                impl_def_id,
+                traits::IntercrateMode::Issue43355,
+                |overlap| {
                     if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                         return Ok((false, false));
                     }
@@ -151,10 +151,9 @@ fn insert(&mut self,
                     } else {
                         Ok((le, ge))
                     }
-                } else {
-                    Ok((false, false))
-                }
-            })?;
+                },
+                || Ok((false, false)),
+            )?;
 
             if le && !ge {
                 debug!("descending as child of TraitRef {:?}",
@@ -171,16 +170,14 @@ fn insert(&mut self,
                 return Ok(Inserted::Replaced(possible_sibling));
             } else {
                 if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
-                    tcx.infer_ctxt().enter(|infcx| {
-                        if let Some(overlap) = traits::overlapping_impls(
-                            &infcx,
-                            possible_sibling,
-                            impl_def_id,
-                            traits::IntercrateMode::Fixed)
-                        {
-                            last_lint = Some(overlap_error(overlap));
-                        }
-                    });
+                    traits::overlapping_impls(
+                        tcx,
+                        possible_sibling,
+                        impl_def_id,
+                        traits::IntercrateMode::Fixed,
+                        |overlap| last_lint = Some(overlap_error(overlap)),
+                        || (),
+                    );
                 }
 
                 // no overlap (error bailed already via ?)
index e1e2798ecb51c052d61d483b742d4a623ef6f4ae..1eb14a222787db67a998033be8cae3e884d47f7b 100644 (file)
@@ -209,6 +209,7 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             super::VariableType(id) => Some(super::VariableType(id)),
             super::ReturnType(id) => Some(super::ReturnType(id)),
             super::SizedReturnType => Some(super::SizedReturnType),
+            super::SizedYieldType => Some(super::SizedYieldType),
             super::RepeatVec => Some(super::RepeatVec),
             super::FieldSized(item) => Some(super::FieldSized(item)),
             super::ConstSized => Some(super::ConstSized),
@@ -526,6 +527,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             super::VariableType(_) |
             super::ReturnType(_) |
             super::SizedReturnType |
+            super::SizedYieldType |
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized(_) |
@@ -574,6 +576,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             super::VariableType(_) |
             super::ReturnType(_) |
             super::SizedReturnType |
+            super::SizedYieldType |
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized(_) |
index 69d07eafdca7a3481a8e03d4f3826d41a354be4b..63b91ff110161f6c7d375071a14bf6be8c0d55c9 100644 (file)
@@ -895,7 +895,8 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     tcx.layout_depth.set(depth+1);
-    let layout = LayoutDetails::compute_uncached(tcx, param_env, ty);
+    let cx = LayoutCx { tcx, param_env };
+    let layout = cx.layout_raw_uncached(ty);
     tcx.layout_depth.set(depth);
 
     layout
@@ -908,13 +909,18 @@ pub fn provide(providers: &mut ty::maps::Providers) {
     };
 }
 
-impl<'a, 'tcx> LayoutDetails {
-    fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        param_env: ty::ParamEnv<'tcx>,
-                        ty: Ty<'tcx>)
-                        -> Result<&'tcx Self, LayoutError<'tcx>> {
-        let cx = (tcx, param_env);
-        let dl = cx.data_layout();
+#[derive(Copy, Clone)]
+pub struct LayoutCx<'tcx, C> {
+    pub tcx: C,
+    pub param_env: ty::ParamEnv<'tcx>
+}
+
+impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
+    fn layout_raw_uncached(self, ty: Ty<'tcx>)
+                           -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
+        let tcx = self.tcx;
+        let param_env = self.param_env;
+        let dl = self.data_layout();
         let scalar_unit = |value: Primitive| {
             let bits = value.size(dl).bits();
             assert!(bits <= 128);
@@ -924,7 +930,7 @@ fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         };
         let scalar = |value: Primitive| {
-            tcx.intern_layout(LayoutDetails::scalar(cx, scalar_unit(value)))
+            tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value)))
         };
         let scalar_pair = |a: Scalar, b: Scalar| {
             let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align);
@@ -1158,13 +1164,13 @@ enum StructKind {
         Ok(match ty.sty {
             // Basic scalars.
             ty::TyBool => {
-                tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+                tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
                     value: Int(I8, false),
                     valid_range: 0..=1
                 }))
             }
             ty::TyChar => {
-                tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+                tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
                     value: Int(I32, false),
                     valid_range: 0..=0x10FFFF
                 }))
@@ -1180,7 +1186,7 @@ enum StructKind {
             ty::TyFnPtr(_) => {
                 let mut ptr = scalar_unit(Pointer);
                 ptr.valid_range.start = 1;
-                tcx.intern_layout(LayoutDetails::scalar(cx, ptr))
+                tcx.intern_layout(LayoutDetails::scalar(self, ptr))
             }
 
             // The never type.
@@ -1198,13 +1204,13 @@ enum StructKind {
 
                 let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
                 if pointee.is_sized(tcx, param_env, DUMMY_SP) {
-                    return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+                    return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
                 }
 
                 let unsized_part = tcx.struct_tail(pointee);
                 let metadata = match unsized_part.sty {
                     ty::TyForeign(..) => {
-                        return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+                        return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
                     }
                     ty::TySlice(_) | ty::TyStr => {
                         scalar_unit(Int(dl.ptr_sized_integer(), false))
@@ -1230,7 +1236,7 @@ enum StructKind {
                     }
                 }
 
-                let element = cx.layout_of(element)?;
+                let element = self.layout_of(element)?;
                 let count = count.val.to_const_int().unwrap().to_u64().unwrap();
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
@@ -1247,7 +1253,7 @@ enum StructKind {
                 })
             }
             ty::TySlice(element) => {
-                let element = cx.layout_of(element)?;
+                let element = self.layout_of(element)?;
                 tcx.intern_layout(LayoutDetails {
                     variants: Variants::Single { index: 0 },
                     fields: FieldPlacement::Array {
@@ -1289,14 +1295,14 @@ enum StructKind {
             // Tuples, generators and closures.
             ty::TyGenerator(def_id, ref substs, _) => {
                 let tys = substs.field_tys(def_id, tcx);
-                univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+                univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
                     StructKind::AlwaysSized)?
             }
 
             ty::TyClosure(def_id, ref substs) => {
                 let tys = substs.upvar_tys(def_id, tcx);
-                univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+                univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
                     StructKind::AlwaysSized)?
             }
@@ -1308,13 +1314,13 @@ enum StructKind {
                     StructKind::MaybeUnsized
                 };
 
-                univariant(&tys.iter().map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+                univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(), kind)?
             }
 
             // SIMD vector types.
             ty::TyAdt(def, ..) if def.repr.simd() => {
-                let element = cx.layout_of(ty.simd_type(tcx))?;
+                let element = self.layout_of(ty.simd_type(tcx))?;
                 let count = ty.simd_size(tcx) as u64;
                 assert!(count > 0);
                 let scalar = match element.abi {
@@ -1350,7 +1356,7 @@ enum StructKind {
                 // Cache the field layouts.
                 let variants = def.variants.iter().map(|v| {
                     v.fields.iter().map(|field| {
-                        cx.layout_of(field.ty(tcx, substs))
+                        self.layout_of(field.ty(tcx, substs))
                     }).collect::<Result<Vec<_>, _>>()
                 }).collect::<Result<Vec<_>, _>>()?;
 
@@ -1430,7 +1436,7 @@ enum StructKind {
                     let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
                     st.variants = Variants::Single { index: v };
                     // Exclude 0 from the range of a newtype ABI NonZero<T>.
-                    if Some(def.did) == cx.tcx().lang_items().non_zero() {
+                    if Some(def.did) == self.tcx.lang_items().non_zero() {
                         match st.abi {
                             Abi::Scalar(ref mut scalar) |
                             Abi::ScalarPair(ref mut scalar, _) => {
@@ -1482,7 +1488,7 @@ enum StructKind {
                         let count = (niche_variants.end - niche_variants.start + 1) as u128;
                         for (field_index, field) in variants[i].iter().enumerate() {
                             let (offset, niche, niche_start) =
-                                match field.find_niche(cx, count)? {
+                                match field.find_niche(self, count)? {
                                     Some(niche) => niche,
                                     None => continue
                                 };
@@ -1687,56 +1693,49 @@ enum StructKind {
     /// This is invoked by the `layout_raw` query to record the final
     /// layout of each type.
     #[inline]
-    fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  ty: Ty<'tcx>,
-                                  param_env: ty::ParamEnv<'tcx>,
-                                  layout: TyLayout<'tcx>) {
+    fn record_layout_for_printing(self, layout: TyLayout<'tcx>) {
         // If we are running with `-Zprint-type-sizes`, record layouts for
         // dumping later. Ignore layouts that are done with non-empty
         // environments or non-monomorphic layouts, as the user only wants
         // to see the stuff resulting from the final trans session.
         if
-            !tcx.sess.opts.debugging_opts.print_type_sizes ||
-            ty.has_param_types() ||
-            ty.has_self_ty() ||
-            !param_env.caller_bounds.is_empty()
+            !self.tcx.sess.opts.debugging_opts.print_type_sizes ||
+            layout.ty.has_param_types() ||
+            layout.ty.has_self_ty() ||
+            !self.param_env.caller_bounds.is_empty()
         {
             return;
         }
 
-        Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
+        self.record_layout_for_printing_outlined(layout)
     }
 
-    fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                           ty: Ty<'tcx>,
-                                           param_env: ty::ParamEnv<'tcx>,
-                                           layout: TyLayout<'tcx>) {
-        let cx = (tcx, param_env);
+    fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
         // (delay format until we actually need it)
         let record = |kind, opt_discr_size, variants| {
-            let type_desc = format!("{:?}", ty);
-            tcx.sess.code_stats.borrow_mut().record_type_size(kind,
-                                                              type_desc,
-                                                              layout.align,
-                                                              layout.size,
-                                                              opt_discr_size,
-                                                              variants);
+            let type_desc = format!("{:?}", layout.ty);
+            self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
+                                                                   type_desc,
+                                                                   layout.align,
+                                                                   layout.size,
+                                                                   opt_discr_size,
+                                                                   variants);
         };
 
-        let adt_def = match ty.sty {
+        let adt_def = match layout.ty.sty {
             ty::TyAdt(ref adt_def, _) => {
-                debug!("print-type-size t: `{:?}` process adt", ty);
+                debug!("print-type-size t: `{:?}` process adt", layout.ty);
                 adt_def
             }
 
             ty::TyClosure(..) => {
-                debug!("print-type-size t: `{:?}` record closure", ty);
+                debug!("print-type-size t: `{:?}` record closure", layout.ty);
                 record(DataTypeKind::Closure, None, vec![]);
                 return;
             }
 
             _ => {
-                debug!("print-type-size t: `{:?}` skip non-nominal", ty);
+                debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
                 return;
             }
         };
@@ -1748,7 +1747,7 @@ fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   layout: TyLayout<'tcx>| {
             let mut min_size = Size::from_bytes(0);
             let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| {
-                match layout.field(cx, i) {
+                match layout.field(self, i) {
                     Err(err) => {
                         bug!("no layout found for field {}: `{:?}`", name, err);
                     }
@@ -1808,18 +1807,18 @@ fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             Variants::NicheFilling { .. } |
             Variants::Tagged { .. } => {
                 debug!("print-type-size `{:#?}` adt general variants def {}",
-                       ty, adt_def.variants.len());
+                       layout.ty, adt_def.variants.len());
                 let variant_infos: Vec<_> =
                     adt_def.variants.iter().enumerate().map(|(i, variant_def)| {
                         let fields: Vec<_> =
                             variant_def.fields.iter().map(|f| f.name).collect();
                         build_variant_info(Some(variant_def.name),
                                             &fields,
-                                            layout.for_variant(cx, i))
+                                            layout.for_variant(self, i))
                     })
                     .collect();
                 record(adt_kind.into(), match layout.variants {
-                    Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)),
+                    Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
                     _ => None
                 }, variant_infos);
             }
@@ -1855,7 +1854,7 @@ pub fn compute(ty: Ty<'tcx>,
         assert!(!ty.has_infer_types());
 
         // First try computing a static layout.
-        let err = match (tcx, param_env).layout_of(ty) {
+        let err = match tcx.layout_of(param_env.and(ty)) {
             Ok(layout) => {
                 return Ok(SizeSkeleton::Known(layout.size));
             }
@@ -2001,15 +2000,15 @@ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx, T: Copy> HasDataLayout for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
     fn data_layout(&self) -> &TargetDataLayout {
-        self.0.data_layout()
+        self.tcx.data_layout()
     }
 }
 
-impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
-        self.0.tcx()
+        self.tcx.tcx()
     }
 }
 
@@ -2042,17 +2041,15 @@ pub trait LayoutOf<T> {
     fn layout_of(self, ty: T) -> Self::TyLayout;
 }
 
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
     type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
 
     /// Computes the layout of a type. Note that this implicitly
     /// executes in "reveal all" mode.
-    #[inline]
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        let (tcx, param_env) = self;
-
-        let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
-        let details = tcx.layout_raw(param_env.reveal_all().and(ty))?;
+        let param_env = self.param_env.reveal_all();
+        let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env);
+        let details = self.tcx.layout_raw(param_env.and(ty))?;
         let layout = TyLayout {
             ty,
             details
@@ -2064,24 +2061,21 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         // completed, to avoid problems around recursive structures
         // and the like. (Admitedly, I wasn't able to reproduce a problem
         // here, but it seems like the right thing to do. -nmatsakis)
-        LayoutDetails::record_layout_for_printing(tcx, ty, param_env, layout);
+        self.record_layout_for_printing(layout);
 
         Ok(layout)
     }
 }
 
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
-                                       ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> {
     type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
 
     /// Computes the layout of a type. Note that this implicitly
     /// executes in "reveal all" mode.
-    #[inline]
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        let (tcx_at, param_env) = self;
-
-        let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
-        let details = tcx_at.layout_raw(param_env.reveal_all().and(ty))?;
+        let param_env = self.param_env.reveal_all();
+        let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
+        let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?;
         let layout = TyLayout {
             ty,
             details
@@ -2093,12 +2087,45 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         // completed, to avoid problems around recursive structures
         // and the like. (Admitedly, I wasn't able to reproduce a problem
         // here, but it seems like the right thing to do. -nmatsakis)
-        LayoutDetails::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
+        let cx = LayoutCx {
+            tcx: *self.tcx,
+            param_env: self.param_env
+        };
+        cx.record_layout_for_printing(layout);
 
         Ok(layout)
     }
 }
 
+// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Computes the layout of a type. Note that this implicitly
+    /// executes in "reveal all" mode.
+    #[inline]
+    pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+                     -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+        let cx = LayoutCx {
+            tcx: self,
+            param_env: param_env_and_ty.param_env
+        };
+        cx.layout_of(param_env_and_ty.value)
+    }
+}
+
+impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
+    /// Computes the layout of a type. Note that this implicitly
+    /// executes in "reveal all" mode.
+    #[inline]
+    pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+                     -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+        let cx = LayoutCx {
+            tcx: self,
+            param_env: param_env_and_ty.param_env
+        };
+        cx.layout_of(param_env_and_ty.value)
+    }
+}
+
 impl<'a, 'tcx> TyLayout<'tcx> {
     pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
         where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>,
index 0c1ebd1a2ba2f2f0c754d1ed8067c4bbdefcbfb1..1593b452cdffc3c4541819d71e1e8cb36a2d58d1 100644 (file)
@@ -390,14 +390,21 @@ impl Iterator<Item=Ty<'tcx>> + 'a
         state.map(move |d| d.ty.subst(tcx, self.substs))
     }
 
+    /// This is the types of the fields of a generate which
+    /// is available before the generator transformation.
+    /// It includes the upvars and the state discriminant which is u32.
+    pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
+        impl Iterator<Item=Ty<'tcx>> + 'a
+    {
+        self.upvar_tys(def_id, tcx).chain(iter::once(tcx.types.u32))
+    }
+
     /// This is the types of all the fields stored in a generator.
     /// It includes the upvars, state types and the state discriminant which is u32.
     pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
         impl Iterator<Item=Ty<'tcx>> + 'a
     {
-        let upvars = self.upvar_tys(def_id, tcx);
-        let state = self.state_tys(def_id, tcx);
-        upvars.chain(iter::once(tcx.types.u32)).chain(state)
+        self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx))
     }
 }
 
index d1095a7819d4aa3729486c5f6d3ed639dfa0ca6c..55f11665f6d0ba83a157680b9ce433bfeab5f02a 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <stdint.h>
 #include <string>
+#include <sstream>
 #include <stdlib.h>
 
 #include "s2wasm.h"
@@ -24,6 +25,7 @@ using namespace wasm;
 
 struct BinaryenRustModule {
   BufferWithRandomAccess buffer;
+  std::string sourceMapJSON;
 };
 
 struct BinaryenRustModuleOptions {
@@ -36,6 +38,7 @@ struct BinaryenRustModuleOptions {
   bool ignoreUnknownSymbols;
   bool debugInfo;
   std::string startFunction;
+  std::string sourceMapUrl;
 
   BinaryenRustModuleOptions() :
     globalBase(0),
@@ -46,7 +49,8 @@ struct BinaryenRustModuleOptions {
     importMemory(false),
     ignoreUnknownSymbols(false),
     debugInfo(false),
-    startFunction("")
+    startFunction(""),
+    sourceMapUrl("")
   {}
 
 };
@@ -73,6 +77,12 @@ BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
   options->startFunction = start;
 }
 
+extern "C" void
+BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
+                                         char *sourceMapUrl) {
+  options->sourceMapUrl = sourceMapUrl;
+}
+
 extern "C" void
 BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
                                             uint64_t stack) {
@@ -106,12 +116,20 @@ BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options,
   {
     WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
     writer.setNamesSection(options->debugInfo);
-    // FIXME: support source maps?
-    // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+
+    std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
+    {
+      sourceMapStream = make_unique<std::ostringstream>();
+      writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
+    }
 
     // FIXME: support symbol maps?
     // writer.setSymbolMap(symbolMap);
     writer.write();
+
+    if (sourceMapStream) {
+      ret->sourceMapJSON = sourceMapStream->str();
+    }
   }
   return ret.release();
 }
@@ -126,6 +144,16 @@ BinaryenRustModuleLen(const BinaryenRustModule *M) {
   return M->buffer.size();
 }
 
+extern "C" const char*
+BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
+  return M->sourceMapJSON.data();
+}
+
+extern "C" size_t
+BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
+  return M->sourceMapJSON.length();
+}
+
 extern "C" void
 BinaryenRustModuleFree(BinaryenRustModule *M) {
   delete M;
index 6c7feb6a7a9d36200cb1bf65d0c3c69a730e9679..36174e11ba04a988012f7724e537dd41c0bfb339 100644 (file)
@@ -51,6 +51,15 @@ pub fn data(&self) -> &[u8] {
             slice::from_raw_parts(ptr, len)
         }
     }
+
+    /// Returns the data of the source map JSON.
+    pub fn source_map(&self) -> &[u8] {
+        unsafe {
+            let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
+            let len = BinaryenRustModuleSourceMapLen(self.ptr);
+            slice::from_raw_parts(ptr, len)
+        }
+    }
 }
 
 impl Drop for Module {
@@ -94,6 +103,15 @@ pub fn start(&mut self, func: &str) -> &mut Self {
         self
     }
 
+    /// Configures a `sourceMappingURL` custom section value for the module.
+    pub fn source_map_url(&mut self, url: &str) -> &mut Self {
+        let url = CString::new(url).unwrap();
+        unsafe {
+            BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
+        }
+        self
+    }
+
     /// Configures how much stack is initially allocated for the module. 1MB is
     /// probably good enough for now.
     pub fn stack(&mut self, amt: u64) -> &mut Self {
@@ -130,6 +148,8 @@ fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions,
         -> *mut BinaryenRustModule;
     fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
     fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
+    fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
+    fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
     fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
 
     fn BinaryenRustModuleOptionsCreate()
@@ -138,6 +158,8 @@ fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions,
                                              debuginfo: bool);
     fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
                                          start: *const libc::c_char);
+    fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
+                                                sourceMapUrl: *const libc::c_char);
     fn BinaryenRustModuleOptionsSetStackAllocation(
         module: *mut BinaryenRustModuleOptions,
         stack: u64,
index 84ca2a9318ab36a226efd894a4dc2ef1ac647ea8..738c0d82ee1b5d0a7a1522ec07614053e7bea29e 100644 (file)
@@ -1068,22 +1068,12 @@ pub fn report_aliasability_violation(&self,
         };
 
         match cause {
-            mc::AliasableStatic => {
-                // This happens when we have an `&mut` or assignment to a
-                // static. We should have already reported a mutability
-                // violation first, but may have continued compiling.
-                self.tcx.sess.delay_span_bug(
-                    span,
-                    &format!("aliasability violation for static `{}`", prefix)
-                );
-                return;
-            }
             mc::AliasableStaticMut => {
                 // This path cannot occur. `static mut X` is not checked
                 // for aliasability violations.
                 span_bug!(span, "aliasability violation for static mut `{}`", prefix)
             }
-            mc::AliasableBorrowed => {}
+            mc::AliasableStatic | mc::AliasableBorrowed => {}
         };
         let blame = cmt.immutability_blame();
         let mut err = match blame {
index ddee122d0a6bd1a4d91d7a248892ced94b2a7bff..7bcd8a185453b11004648411493a1bf70febb5dd 100644 (file)
@@ -77,7 +77,7 @@ fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
                 continue
             }
 
-            let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' ');
+            let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
 
             // Ok, every name wasn't used mutably, so issue a warning that this
             // didn't need to be mutable.
index 418bd4b5effc6b08ba01d3a50dc4e4313fbad51a..8e4ec93c14baebae44f7ca13e58ff099ca474883 100644 (file)
@@ -17,7 +17,6 @@
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::LayoutOf;
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::subst::{Substs, Subst};
 use rustc::util::common::ErrorReported;
@@ -313,7 +312,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
             let layout_of = |ty: Ty<'tcx>| {
                 let ty = tcx.erase_regions(&ty);
-                (tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| {
+                tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
                     ConstEvalErr { span: e.span, kind: LayoutError(err) }
                 })
             };
@@ -328,6 +327,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                     return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
                         tcx.sess.target.usize_ty).unwrap()))));
                 }
+                "type_id" => {
+                    let type_id = tcx.type_id_hash(substs.type_at(0));
+                    return Ok(mk_const(Integral(U64(type_id))));
+                }
                 _ => signal!(e, TypeckError)
             }
           }
index e97d83ed1ee5ab0670c6dc030ed8fa1d8a7042f5..50c19b5a99a540d2a6e3bff54aafa512b4461713 100644 (file)
@@ -121,23 +121,8 @@ macro_rules! controller_entry_point {
         };
 
         let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
-
-        // Ensure the source file isn't accidentally overwritten during compilation.
-        match *input_path {
-            Some(ref input_path) => {
-                if outputs.contains_path(input_path) && sess.opts.will_create_output_file() {
-                    sess.err(&format!(
-                        "the input file \"{}\" would be overwritten by the generated executable",
-                        input_path.display()));
-                    return Err(CompileIncomplete::Stopped);
-                }
-            },
-            None => {}
-        }
-
         let crate_name =
             ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
-
         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
             phase_2_configure_and_expand(
                 sess,
@@ -157,7 +142,29 @@ macro_rules! controller_entry_point {
             )?
         };
 
-        write_out_deps(sess, &outputs, &crate_name);
+        let output_paths = generated_output_paths(sess, &outputs, output.is_some(), &crate_name);
+
+        // Ensure the source file isn't accidentally overwritten during compilation.
+        if let Some(ref input_path) = *input_path {
+            if sess.opts.will_create_output_file() {
+                if output_contains_path(&output_paths, input_path) {
+                    sess.err(&format!(
+                        "the input file \"{}\" would be overwritten by the generated \
+                        executable",
+                        input_path.display()));
+                    return Err(CompileIncomplete::Stopped);
+                }
+                if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
+                    sess.err(&format!(
+                        "the generated executable for the input file \"{}\" conflicts with the \
+                        existing directory \"{}\"",
+                        input_path.display(), dir_path.display()));
+                    return Err(CompileIncomplete::Stopped);
+                }
+            }
+        }
+
+        write_out_deps(sess, &outputs, &output_paths);
         if sess.opts.output_types.contains_key(&OutputType::DepInfo) &&
             sess.opts.output_types.keys().count() == 1 {
             return Ok(())
@@ -1101,16 +1108,22 @@ fn escape_dep_filename(filename: &FileName) -> String {
     filename.to_string().replace(" ", "\\ ")
 }
 
-fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
+// Returns all the paths that correspond to generated files.
+fn generated_output_paths(sess: &Session,
+                          outputs: &OutputFilenames,
+                          exact_name: bool,
+                          crate_name: &str) -> Vec<PathBuf> {
     let mut out_filenames = Vec::new();
     for output_type in sess.opts.output_types.keys() {
         let file = outputs.path(*output_type);
         match *output_type {
-            OutputType::Exe => {
-                for output in sess.crate_types.borrow().iter() {
+            // If the filename has been overridden using `-o`, it will not be modified
+            // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
+            OutputType::Exe if !exact_name => {
+                for crate_type in sess.crate_types.borrow().iter() {
                     let p = ::rustc_trans_utils::link::filename_for_input(
                         sess,
-                        *output,
+                        *crate_type,
                         crate_name,
                         outputs
                     );
@@ -1125,7 +1138,46 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
             }
         }
     }
+    out_filenames
+}
+
+// Runs `f` on every output file path and returns the first non-None result, or None if `f`
+// returns None for every file path.
+fn check_output<F, T>(output_paths: &Vec<PathBuf>, f: F) -> Option<T>
+        where F: Fn(&PathBuf) -> Option<T> {
+            for output_path in output_paths {
+                if let Some(result) = f(output_path) {
+                    return Some(result);
+                }
+            }
+            None
+}
 
+pub fn output_contains_path(output_paths: &Vec<PathBuf>, input_path: &PathBuf) -> bool {
+    let input_path = input_path.canonicalize().ok();
+    if input_path.is_none() {
+        return false
+    }
+    let check = |output_path: &PathBuf| {
+        if output_path.canonicalize().ok() == input_path {
+            Some(())
+        } else { None }
+    };
+    check_output(output_paths, check).is_some()
+}
+
+pub fn output_conflicts_with_dir(output_paths: &Vec<PathBuf>) -> Option<PathBuf> {
+    let check = |output_path: &PathBuf| {
+        if output_path.is_dir() {
+            Some(output_path.clone())
+        } else { None }
+    };
+    check_output(output_paths, check)
+}
+
+fn write_out_deps(sess: &Session,
+                  outputs: &OutputFilenames,
+                  out_filenames: &Vec<PathBuf>) {
     // Write out dependency rules to the dep-info file if requested
     if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
         return;
@@ -1144,7 +1196,7 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
                                          .map(|fmap| escape_dep_filename(&fmap.name))
                                          .collect();
             let mut file = fs::File::create(&deps_filename)?;
-            for path in &out_filenames {
+            for path in out_filenames {
                 write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
             }
 
@@ -1327,7 +1379,10 @@ pub fn build_output_filenames(input: &Input,
                 Some(out_file.clone())
             };
             if *odir != None {
-                sess.warn("ignoring --out-dir flag due to -o flag.");
+                sess.warn("ignoring --out-dir flag due to -o flag");
+            }
+            if !sess.opts.cg.extra_filename.is_empty() {
+                sess.warn("ignoring -C extra-filename flag due to -o flag");
             }
 
             let cur_dir = Path::new("");
index 2e654fe9929a6af7801755994f0dcc8147c29043..40e4efb397d305087b223e4cad8d8143f3d771a7 100644 (file)
@@ -222,6 +222,7 @@ pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String)
             }],
             msg: msg.to_owned(),
             show_code_when_inline: false,
+            approximate: false,
         });
         self
     }
@@ -252,6 +253,7 @@ pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &m
             }],
             msg: msg.to_owned(),
             show_code_when_inline: true,
+            approximate: false,
         });
         self
     }
@@ -267,6 +269,41 @@ pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>
             }).collect(),
             msg: msg.to_owned(),
             show_code_when_inline: true,
+            approximate: false,
+        });
+        self
+    }
+
+    /// This is a suggestion that may contain mistakes or fillers and should
+    /// be read and understood by a human.
+    pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
+                                       suggestion: String) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: vec![Substitution {
+                parts: vec![SubstitutionPart {
+                    snippet: suggestion,
+                    span: sp,
+                }],
+            }],
+            msg: msg.to_owned(),
+            show_code_when_inline: true,
+            approximate: true,
+        });
+        self
+    }
+
+    pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
+                                        suggestions: Vec<String>) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: suggestions.into_iter().map(|snippet| Substitution {
+                parts: vec![SubstitutionPart {
+                    snippet,
+                    span: sp,
+                }],
+            }).collect(),
+            msg: msg.to_owned(),
+            show_code_when_inline: true,
+            approximate: true,
         });
         self
     }
index 61674ada6fa63c1bc37a7ff3e7b09d92a57801e7..2536fc648c70ad693f8356b6dfc8d2bf9345e11f 100644 (file)
@@ -186,6 +186,16 @@ pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self
                                      msg: &str,
                                      suggestions: Vec<String>)
                                      -> &mut Self);
+    forward!(pub fn span_approximate_suggestion(&mut self,
+                                                sp: Span,
+                                                msg: &str,
+                                                suggestion: String)
+                                                -> &mut Self);
+    forward!(pub fn span_approximate_suggestions(&mut self,
+                                                 sp: Span,
+                                                 msg: &str,
+                                                 suggestions: Vec<String>)
+                                                 -> &mut Self);
     forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
 
index 47eb04621a126935fef64637f90f98a271a59899..236698ed2d45d77ba5099953daf89ba83b626201 100644 (file)
@@ -83,6 +83,12 @@ pub struct CodeSuggestion {
     pub substitutions: Vec<Substitution>,
     pub msg: String,
     pub show_code_when_inline: bool,
+    /// Whether or not the suggestion is approximate
+    ///
+    /// Sometimes we may show suggestions with placeholders,
+    /// which are useful for users but not useful for
+    /// tools like rustfix
+    pub approximate: bool,
 }
 
 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
index 6035f33c822cee1eedf6b87ad412c1b4d9f87fb8..7d416f13ffc8a0f77d5f951c1641c2e07534d0f2 100644 (file)
 
 // Code for annotating snippets.
 
-use syntax_pos::{Span, FileMap};
-use CodeMapper;
-use std::rc::Rc;
 use Level;
 
-#[derive(Clone)]
-pub struct SnippetData {
-    codemap: Rc<CodeMapper>,
-    files: Vec<FileInfo>,
-}
-
-#[derive(Clone)]
-pub struct FileInfo {
-    file: Rc<FileMap>,
-
-    /// The "primary file", if any, gets a `-->` marker instead of
-    /// `>>>`, and has a line-number/column printed and not just a
-    /// filename (other files are not guaranteed to have line numbers
-    /// or columns). It appears first in the listing. It is known to
-    /// contain at least one primary span, though primary spans (which
-    /// are designated with `^^^`) may also occur in other files.
-    primary_span: Option<Span>,
-
-    lines: Vec<Line>,
-}
-
 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
 pub struct Line {
     pub line_index: usize,
index e0999db6e3e66d3930e9c6ac6ffd4470023aedfd..e7e4119b9999bee72eb0558cfe216057e8e9e176 100644 (file)
@@ -437,8 +437,8 @@ fn check_type_for_ffi(&self,
                             // repr(transparent) types are allowed to have arbitrary ZSTs, not just
                             // PhantomData -- skip checking all ZST fields
                             if def.repr.transparent() {
-                                let is_zst = (cx, cx.param_env(field.did))
-                                    .layout_of(field_ty)
+                                let is_zst = cx
+                                    .layout_of(cx.param_env(field.did).and(field_ty))
                                     .map(|layout| layout.is_zst())
                                     .unwrap_or(false);
                                 if is_zst {
index ef6475f9ee4c7b403aa607845363774d633425aa..56f863ab3aa84e6ae881cab222e422793ea3cdbd 100644 (file)
@@ -302,19 +302,38 @@ fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
             Assign(_, ref value) => (value, "assigned value", false),
             AssignOp(.., ref value) => (value, "assigned value", false),
             InPlace(_, ref value) => (value, "emplacement value", false),
-            Call(_, ref args) => {
-                for arg in args {
-                    self.check_unused_parens_core(cx, arg, "function argument", false)
+            // either function/method call, or something this lint doesn't care about
+            ref call_or_other => {
+                let args_to_check;
+                let call_kind;
+                match *call_or_other {
+                    Call(_, ref args) => {
+                        call_kind = "function";
+                        args_to_check = &args[..];
+                    },
+                    MethodCall(_, ref args) => {
+                        call_kind = "method";
+                        // first "argument" is self (which sometimes needs parens)
+                        args_to_check = &args[1..];
+                    }
+                    // actual catch-all arm
+                    _ => { return; }
                 }
-                return;
-            },
-            MethodCall(_, ref args) => {
-                for arg in &args[1..] { // first "argument" is self (which sometimes needs parens)
-                    self.check_unused_parens_core(cx, arg, "method argument", false)
+                // Don't lint if this is a nested macro expansion: otherwise, the lint could
+                // trigger in situations that macro authors shouldn't have to care about, e.g.,
+                // when a parenthesized token tree matched in one macro expansion is matched as
+                // an expression in another and used as a fn/method argument (Issue #47775)
+                if e.span.ctxt().outer().expn_info()
+                    .map_or(false, |info| info.call_site.ctxt().outer()
+                            .expn_info().is_some()) {
+                        return;
+                }
+                let msg = format!("{} argument", call_kind);
+                for arg in args_to_check {
+                    self.check_unused_parens_core(cx, arg, &msg, false);
                 }
                 return;
             }
-            _ => return,
         };
         self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
     }
index 7bd3b6e39f053b46ca7ab2ce3558049c6ede6ee6..1ea897bf27ca544732ed7aa15c1941f70106eff5 100644 (file)
@@ -362,33 +362,20 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
         let scope_tree = borrows.0.scope_tree();
         let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap();
 
-        match root_place {
-            &Place::Local(local) => {
-                if let Some(_) = self.storage_dead_or_drop_error_reported_l.replace(local) {
-                    debug!("report_does_not_live_long_enough({:?}): <suppressed>",
-                           (borrow, drop_span));
-                    return
-                }
-            }
-            &Place::Static(ref statik) => {
-                if let Some(_) = self.storage_dead_or_drop_error_reported_s
-                    .replace(statik.def_id)
-                {
-                    debug!("report_does_not_live_long_enough({:?}): <suppressed>",
-                           (borrow, drop_span));
-                    return
-                }
-            },
-            &Place::Projection(_) =>
-                unreachable!("root_place is an unreachable???")
-        };
-
         let borrow_span = self.mir.source_info(borrow.location).span;
         let proper_span = match *root_place {
             Place::Local(local) => self.mir.local_decls[local].source_info.span,
             _ => drop_span,
         };
 
+        if self.access_place_error_reported.contains(&(root_place.clone(), borrow_span)) {
+            debug!("suppressing access_place error when borrow doesn't live long enough for {:?}",
+                   borrow_span);
+            return;
+        }
+
+        self.access_place_error_reported.insert((root_place.clone(), borrow_span));
+
         match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
             (RegionKind::ReScope(_), Some(name)) => {
                 self.report_scoped_local_value_does_not_live_long_enough(
@@ -746,12 +733,12 @@ fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
                     self.describe_field_from_ty(&tnm.ty, field)
                 }
                 ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
-                ty::TyClosure(closure_def_id, _) => {
+                ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
                     // Convert the def-id into a node-id. node-ids are only valid for
                     // the local code in the current crate, so this returns an `Option` in case
                     // the closure comes from another crate. But in that case we wouldn't
                     // be borrowck'ing it, so we can just unwrap:
-                    let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
+                    let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
 
                     self.tcx.hir.name(freevar.var_id()).to_string()
index 9a6d83b8eb75904c81d2b45a128992cf328c4dde..d90209993aa48f0bc6476ee574b03cdfb9389a3e 100644 (file)
@@ -17,7 +17,7 @@
 use rustc::infer::InferCtxt;
 use rustc::ty::{self, ParamEnv, TyCtxt};
 use rustc::ty::maps::Providers;
-use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Place};
+use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place};
 use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
 use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
 use rustc::mir::ClosureRegionRequirements;
@@ -228,8 +228,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
             hir::BodyOwnerKind::Fn => true,
         },
-        storage_dead_or_drop_error_reported_l: FxHashSet(),
-        storage_dead_or_drop_error_reported_s: FxHashSet(),
+        access_place_error_reported: FxHashSet(),
         reservation_error_reported: FxHashSet(),
         nonlexical_regioncx: opt_regioncx.clone(),
     };
@@ -294,12 +293,12 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     /// I'm not sure this is the right approach - @eddyb could you try and
     /// figure this out?
     locals_are_invalidated_at_exit: bool,
-    /// This field keeps track of when storage dead or drop errors are reported
-    /// in order to stop duplicate error reporting and identify the conditions required
-    /// for a "temporary value dropped here while still borrowed" error. See #45360.
-    storage_dead_or_drop_error_reported_l: FxHashSet<Local>,
-    /// Same as the above, but for statics (thread-locals)
-    storage_dead_or_drop_error_reported_s: FxHashSet<DefId>,
+    /// This field keeps track of when borrow errors are reported in the access_place function
+    /// so that there is no duplicate reporting. This field cannot also be used for the conflicting
+    /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
+    /// of the `Span` type (while required to mute some errors) stops the muting of the reservation
+    /// errors.
+    access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>,
     /// This field keeps track of when borrow conflict errors are reported
     /// for reservations, so that we don't report seemingly duplicate
     /// errors for corresponding activations
@@ -348,6 +347,13 @@ fn visit_statement_entry(
 
         match stmt.kind {
             StatementKind::Assign(ref lhs, ref rhs) => {
+                self.consume_rvalue(
+                    ContextKind::AssignRhs.new(location),
+                    (rhs, span),
+                    location,
+                    flow_state,
+                );
+
                 self.mutate_place(
                     ContextKind::AssignLhs.new(location),
                     (lhs, span),
@@ -355,13 +361,6 @@ fn visit_statement_entry(
                     JustWrite,
                     flow_state,
                 );
-
-                self.consume_rvalue(
-                    ContextKind::AssignRhs.new(location),
-                    (rhs, span),
-                    location,
-                    flow_state,
-                );
             }
             StatementKind::SetDiscriminant {
                 ref place,
@@ -726,12 +725,8 @@ fn access_place(
 
         if let Activation(_, borrow_index) = rw {
             if self.reservation_error_reported.contains(&place_span.0) {
-                debug!(
-                    "skipping access_place for activation of invalid reservation \
-                     place: {:?} borrow_index: {:?}",
-                    place_span.0,
-                    borrow_index
-                );
+                debug!("skipping access_place for activation of invalid reservation \
+                     place: {:?} borrow_index: {:?}", place_span.0, borrow_index);
                 return AccessErrorsReported {
                     mutability_error: false,
                     conflict_error: true,
@@ -739,11 +734,26 @@ fn access_place(
             }
         }
 
+        if self.access_place_error_reported.contains(&(place_span.0.clone(), place_span.1)) {
+            debug!("access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
+                   place_span, kind);
+            return AccessErrorsReported {
+                mutability_error: false,
+                conflict_error: true,
+            };
+        }
+
         let mutability_error =
             self.check_access_permissions(place_span, rw, is_local_mutation_allowed);
         let conflict_error =
             self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
 
+        if conflict_error || mutability_error {
+            debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`",
+                   place_span, kind);
+            self.access_place_error_reported.insert((place_span.0.clone(), place_span.1));
+        }
+
         AccessErrorsReported {
             mutability_error,
             conflict_error,
@@ -829,15 +839,15 @@ fn check_access_for_conflict(
                                 place_span.0
                             );
                             this.reservation_error_reported.insert(place_span.0.clone());
-                        }
+                        },
                         Activation(_, activating) => {
                             debug!(
                                 "observing check_place for activation of \
                                  borrow_index: {:?}",
                                 activating
                             );
-                        }
-                        Read(..) | Write(..) => {}
+                        },
+                        Read(..) | Write(..) => {},
                     }
 
                     match kind {
index 6c2037810d3260d831b5227f6f6b88fcd18428e2..a50b99937475eba58f30a0a67ebf517a6d307460 100644 (file)
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::mir::Local;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::traits;
+use rustc::infer::InferOk;
 use rustc::util::common::ErrorReported;
+use borrow_check::nll::type_check::AtLocation;
 use rustc_data_structures::fx::FxHashSet;
 use syntax::codemap::DUMMY_SP;
 use util::liveness::LivenessResults;
@@ -184,48 +187,86 @@ fn add_drop_live_constraint(
             location
         );
 
-        let tcx = self.cx.infcx.tcx;
-        let mut types = vec![(dropped_ty, 0)];
-        let mut known = FxHashSet();
-        while let Some((ty, depth)) = types.pop() {
-            let span = DUMMY_SP; // FIXME
-            let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
-                Ok(result) => result,
-                Err(ErrorReported) => {
-                    continue;
-                }
-            };
-
-            let ty::DtorckConstraint {
-                outlives,
-                dtorck_types,
-            } = result;
-
-            // All things in the `outlives` array may be touched by
-            // the destructor and must be live at this point.
-            for outlive in outlives {
-                let cause = Cause::DropVar(dropped_local, location);
-                self.push_type_live_constraint(outlive, location, cause);
-            }
+        // If we end visiting the same type twice (usually due to a cycle involving
+        // associated types), we need to ensure that its region types match up with the type
+        // we added to the 'known' map the first time around. For this reason, we need
+        // our infcx to hold onto its calculated region constraints after each call
+        // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
+        // type will end up instantiating the type with a new set of inference variables
+        // Since this new type will never be in 'known', we end up looping forever.
+        //
+        // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
+        // ourselves in one large 'fully_perform_op' callback.
+        let (type_constraints, kind_constraints) = self.cx.fully_perform_op(location.at_self(),
+            |cx| {
+
+            let tcx = cx.infcx.tcx;
+            let mut selcx = traits::SelectionContext::new(cx.infcx);
+            let cause = cx.misc(cx.last_span);
+
+            let mut types = vec![(dropped_ty, 0)];
+            let mut final_obligations = Vec::new();
+            let mut type_constraints = Vec::new();
+            let mut kind_constraints = Vec::new();
 
-            // However, there may also be some types that
-            // `dtorck_constraint_for_ty` could not resolve (e.g.,
-            // associated types and parameters). We need to normalize
-            // associated types here and possibly recursively process.
-            for ty in dtorck_types {
-                let ty = self.cx.normalize(&ty, location);
-                let ty = self.cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
-                match ty.sty {
-                    ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
-                        let cause = Cause::DropVar(dropped_local, location);
-                        self.push_type_live_constraint(ty, location, cause);
+            let mut known = FxHashSet();
+
+            while let Some((ty, depth)) = types.pop() {
+                let span = DUMMY_SP; // FIXME
+                let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
+                    Ok(result) => result,
+                    Err(ErrorReported) => {
+                        continue;
                     }
+                };
+
+                let ty::DtorckConstraint {
+                    outlives,
+                    dtorck_types,
+                } = result;
+
+                // All things in the `outlives` array may be touched by
+                // the destructor and must be live at this point.
+                for outlive in outlives {
+                    let cause = Cause::DropVar(dropped_local, location);
+                    kind_constraints.push((outlive, location, cause));
+                }
 
-                    _ => if known.insert(ty) {
-                        types.push((ty, depth + 1));
-                    },
+                // However, there may also be some types that
+                // `dtorck_constraint_for_ty` could not resolve (e.g.,
+                // associated types and parameters). We need to normalize
+                // associated types here and possibly recursively process.
+                for ty in dtorck_types {
+                    let traits::Normalized { value: ty, obligations } =
+                        traits::normalize(&mut selcx, cx.param_env, cause.clone(), &ty);
+
+                    final_obligations.extend(obligations);
+
+                    let ty = cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
+                    match ty.sty {
+                        ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
+                            let cause = Cause::DropVar(dropped_local, location);
+                            type_constraints.push((ty, location, cause));
+                        }
+
+                        _ => if known.insert(ty) {
+                            types.push((ty, depth + 1));
+                        },
+                    }
                 }
             }
+
+            Ok(InferOk {
+                value: (type_constraints, kind_constraints), obligations: final_obligations
+            })
+        }).unwrap();
+
+        for (ty, location, cause) in type_constraints {
+            self.push_type_live_constraint(ty, location, cause);
+        }
+
+        for (kind, location, cause) in kind_constraints {
+            self.push_type_live_constraint(kind, location, cause);
         }
     }
 }
index 015eb8a3b6643bfddf5ddaed9837fc899cd70433..c0c680a4ddcbceae0b361f7af3ffb86800a1e3e5 100644 (file)
@@ -374,13 +374,20 @@ fn sanitize_place(
             }
         };
         if let PlaceContext::Copy = context {
-            let ty = place_ty.to_ty(self.tcx());
-            if self.cx
-                .infcx
-                .type_moves_by_default(self.cx.param_env, ty, DUMMY_SP)
-            {
-                span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty);
-            }
+            let tcx = self.tcx();
+            let trait_ref = ty::TraitRef {
+                def_id: tcx.lang_items().copy_trait().unwrap(),
+                substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
+            };
+
+            // In order to have a Copy operand, the type T of the value must be Copy. Note that we
+            // prove that T: Copy, rather than using the type_moves_by_default test. This is
+            // important because type_moves_by_default ignores the resulting region obligations and
+            // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
+            // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
+            // fully apply: in effect, the rule is that if a value of some type could implement
+            // Copy, then it must.
+            self.cx.prove_trait_ref(trait_ref, location);
         }
         place_ty
     }
@@ -533,15 +540,17 @@ fn field_ty(
                     }
                 }
                 ty::TyGenerator(def_id, substs, _) => {
-                    // Try upvars first. `field_tys` requires final optimized MIR.
-                    if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) {
+                    // Try pre-transform fields first (upvars and current state)
+                    if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
                         return Ok(ty);
                     }
 
+                    // Then try `field_tys` which contains all the fields, but it
+                    // requires the final optimized MIR.
                     return match substs.field_tys(def_id, tcx).nth(field.index()) {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: substs.field_tys(def_id, tcx).count() + 1,
+                            field_count: substs.field_tys(def_id, tcx).count(),
                         }),
                     };
                 }
@@ -1233,13 +1242,16 @@ fn aggregate_field_ty(
                 }
             }
             AggregateKind::Generator(def_id, substs, _) => {
-                if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) {
+                // Try pre-transform fields first (upvars and current state)
+                if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) {
                     Ok(ty)
                 } else {
+                    // Then try `field_tys` which contains all the fields, but it
+                    // requires the final optimized MIR.
                     match substs.field_tys(def_id, tcx).nth(field_index) {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: substs.field_tys(def_id, tcx).count() + 1,
+                            field_count: substs.field_tys(def_id, tcx).count(),
                         }),
                     }
                 }
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
new file mode 100644 (file)
index 0000000..244e8b5
--- /dev/null
@@ -0,0 +1,118 @@
+// 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.
+
+pub use super::*;
+
+use rustc::mir::*;
+use rustc::mir::visit::Visitor;
+use dataflow::BitDenotation;
+
+/// This calculates if any part of a MIR local could have previously been borrowed.
+/// This means that once a local has been borrowed, its bit will always be set
+/// from that point and onwards, even if the borrow ends. You could also think of this
+/// as computing the lifetimes of infinite borrows.
+/// This is used to compute which locals are live during a yield expression for
+/// immovable generators.
+#[derive(Copy, Clone)]
+pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> {
+    mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
+    pub fn new(mir: &'a Mir<'tcx>)
+               -> Self {
+        HaveBeenBorrowedLocals { mir: mir }
+    }
+
+    pub fn mir(&self) -> &Mir<'tcx> {
+        self.mir
+    }
+}
+
+impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
+    type Idx = Local;
+    fn name() -> &'static str { "has_been_borrowed_locals" }
+    fn bits_per_block(&self) -> usize {
+        self.mir.local_decls.len()
+    }
+
+    fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
+        // Nothing is borrowed on function entry
+    }
+
+    fn statement_effect(&self,
+                        sets: &mut BlockSets<Local>,
+                        loc: Location) {
+        BorrowedLocalsVisitor {
+            sets,
+        }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
+    }
+
+    fn terminator_effect(&self,
+                         sets: &mut BlockSets<Local>,
+                         loc: Location) {
+        BorrowedLocalsVisitor {
+            sets,
+        }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
+    }
+
+    fn propagate_call_return(&self,
+                             _in_out: &mut IdxSet<Local>,
+                             _call_bb: mir::BasicBlock,
+                             _dest_bb: mir::BasicBlock,
+                             _dest_place: &mir::Place) {
+        // Nothing to do when a call returns successfully
+    }
+}
+
+impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
+    #[inline]
+    fn join(&self, pred1: usize, pred2: usize) -> usize {
+        pred1 | pred2 // "maybe" means we union effects of both preds
+    }
+}
+
+impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
+    #[inline]
+    fn bottom_value() -> bool {
+        false // bottom = unborrowed
+    }
+}
+
+struct BorrowedLocalsVisitor<'b, 'c: 'b> {
+    sets: &'b mut BlockSets<'c, Local>,
+}
+
+fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
+    match *place {
+        Place::Local(l) => Some(l),
+        Place::Static(..) => None,
+        Place::Projection(ref proj) => {
+            match proj.elem {
+                ProjectionElem::Deref => None,
+                _ => find_local(&proj.base)
+            }
+        }
+    }
+}
+
+impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
+    fn visit_rvalue(&mut self,
+                    rvalue: &Rvalue<'tcx>,
+                    location: Location) {
+        if let Rvalue::Ref(_, _, ref place) = *rvalue {
+            if let Some(local) = find_local(place) {
+                self.sets.gen(&local);
+            }
+        }
+
+        self.super_rvalue(rvalue, location)
+    }
+}
index 632bb5b34284da8e3eb2fab4607dbbc01437a3fb..80990bcc080891ef93478a602019248137560710 100644 (file)
@@ -396,8 +396,7 @@ fn statement_effect_on_borrows(&self,
                         // Issue #46746: Two-phase borrows handles
                         // stmts of form `Tmp = &mut Borrow` ...
                         match lhs {
-                            Place::Local(..) => {} // okay
-                            Place::Static(..) => unreachable!(), // (filtered by is_unsafe_place)
+                            Place::Local(..) | Place::Static(..) => {} // okay
                             Place::Projection(..) => {
                                 // ... can assign into projections,
                                 // e.g. `box (&mut _)`. Current
index e7c15625cbe2be9bbf946c81395ef3a0d8cde61c..c5f5492cd2c2c20cefc36c6c75e1ab5f6cbebee1 100644 (file)
 
 pub use self::storage_liveness::*;
 
+mod borrowed_locals;
+
+pub use self::borrowed_locals::*;
+
 #[allow(dead_code)]
 pub(super) mod borrows;
 
index bd63198ecd0d273c127723a49efb48e62b00345d..291c22b5e1ed0f0aa32081534a97ff24f396cd21 100644 (file)
@@ -30,6 +30,7 @@
 pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
 pub use self::impls::EverInitializedPlaces;
 pub use self::impls::borrows::{Borrows, BorrowData};
+pub use self::impls::HaveBeenBorrowedLocals;
 pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex};
 pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
 pub(crate) use self::drop_flag_effects::*;
index 848c2d3c811e99495a83aade112bffb9a4b100c6..317b038c4829566bdddd7e9189553b60ca5e4431 100644 (file)
@@ -145,7 +145,39 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     arg: expr.to_ref(),
                 },
             };
-            ExprKind::Cast { source: expr.to_ref() }
+            let cast_expr = Expr {
+                temp_lifetime,
+                ty: adjustment.target,
+                span,
+                kind: ExprKind::Cast { source: expr.to_ref() }
+            };
+
+            // To ensure that both implicit and explicit coercions are
+            // handled the same way, we insert an extra layer of indirection here.
+            // For explicit casts (e.g. 'foo as *const T'), the source of the 'Use'
+            // will be an ExprKind::Hair with the appropriate cast expression. Here,
+            // we make our Use source the generated Cast from the original coercion.
+            //
+            // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by
+            // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary.
+            // Ordinary, this is identical to using the cast directly as an rvalue. However, if the
+            // source of the cast was previously borrowed as mutable, storing the cast in a
+            // temporary gives the source a chance to expire before the cast is used. For
+            // structs with a self-referential *mut ptr, this allows assignment to work as
+            // expected.
+            //
+            // For example, consider the type 'struct Foo { field: *mut Foo }',
+            // The method 'fn bar(&mut self) { self.field = self }'
+            // triggers a coercion from '&mut self' to '*mut self'. In order
+            // for the assignment to be valid, the implicit borrow
+            // of 'self' involved in the coercion needs to end before the local
+            // containing the '*mut T' is assigned to 'self.field' - otherwise,
+            // we end up trying to assign to 'self.field' while we have another mutable borrow
+            // active.
+            //
+            // We only need to worry about this kind of thing for coercions from refs to ptrs,
+            // since they get rid of a borrow implicitly.
+            ExprKind::Use { source: cast_expr.to_ref() }
         }
         Adjust::Unsize => {
             ExprKind::Unsize { source: expr.to_ref() }
index 2913f72460e3e7a520e77f6320d87fc31098a2ed..d3b084fde6ab899c6ec55944dea4968c2e7fb260 100644 (file)
@@ -243,6 +243,12 @@ fn call_intrinsic<'a>(
                 ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
             }
 
+            "type_id" => {
+                let ty = substs.type_at(0);
+                let type_id = ecx.tcx.type_id_hash(ty) as u128;
+                ecx.write_primval(dest, PrimVal::from_u128(type_id), dest_layout.ty)?;
+            }
+
             name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()),
         }
 
index baec0fea50f1ef18df029ea03cc885403679d8f7..02fcb69fef5acff1889cd234cd77650d6603cfd9 100644 (file)
@@ -172,7 +172,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx
     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        (self.tcx, self.param_env).layout_of(ty)
+        self.tcx.layout_of(self.param_env.and(ty))
             .map_err(|layout| EvalErrorKind::Layout(layout).into())
     }
 }
index c206d0ea9b5fd6e6ee04ad96ddcaa59c4d105e23..42ffcc194ca8c4750a8ac9d33b8668ebb56c0178 100644 (file)
@@ -294,22 +294,25 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     debug!("build_clone_shim(def_id={:?})", def_id);
 
-    let mut builder = CloneShimBuilder::new(tcx, def_id);
+    let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
     let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span);
 
+    let dest = Place::Local(RETURN_PLACE);
+    let src = Place::Local(Local::new(1+0)).deref();
+
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
         ty::TyArray(ty, len) => {
             let len = len.val.to_const_int().unwrap().to_u64().unwrap();
-            builder.array_shim(ty, len)
+            builder.array_shim(dest, src, ty, len)
         }
         ty::TyClosure(def_id, substs) => {
             builder.tuple_like_shim(
-                &substs.upvar_tys(def_id, tcx).collect::<Vec<_>>(),
-                AggregateKind::Closure(def_id, substs)
+                dest, src,
+                substs.upvar_tys(def_id, tcx)
             )
         }
-        ty::TyTuple(tys, _) => builder.tuple_like_shim(&**tys, AggregateKind::Tuple),
+        ty::TyTuple(tys, _) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
         _ => {
             bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
         }
@@ -328,8 +331,14 @@ struct CloneShimBuilder<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Self {
-        let sig = tcx.fn_sig(def_id);
+    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+           def_id: DefId,
+           self_ty: Ty<'tcx>) -> Self {
+        // we must subst the self_ty because it's
+        // otherwise going to be TySelf and we can't index
+        // or access fields of a Place of type TySelf.
+        let substs = tcx.mk_substs_trait(self_ty, &[]);
+        let sig = tcx.fn_sig(def_id).subst(tcx, substs);
         let sig = tcx.erase_late_bound_regions(&sig);
         let span = tcx.def_span(def_id);
 
@@ -377,6 +386,14 @@ fn block(
         })
     }
 
+    /// Gives the index of an upcoming BasicBlock, with an offset.
+    /// offset=0 will give you the index of the next BasicBlock,
+    /// offset=1 will give the index of the next-to-next block,
+    /// offset=-1 will give you the index of the last-created block
+    fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
+        BasicBlock::new(self.blocks.len() + offset)
+    }
+
     fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
         Statement {
             source_info: self.source_info(),
@@ -404,11 +421,12 @@ fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
 
     fn make_clone_call(
         &mut self,
+        dest: Place<'tcx>,
+        src: Place<'tcx>,
         ty: Ty<'tcx>,
-        rcvr_field: Place<'tcx>,
         next: BasicBlock,
         cleanup: BasicBlock
-    ) -> Place<'tcx> {
+    ) {
         let tcx = self.tcx;
 
         let substs = Substs::for_item(
@@ -439,13 +457,11 @@ fn make_clone_call(
             })
         );
 
-        let loc = self.make_place(Mutability::Not, ty);
-
-        // `let ref_loc: &ty = &rcvr_field;`
+        // `let ref_loc: &ty = &src;`
         let statement = self.make_statement(
             StatementKind::Assign(
                 ref_loc.clone(),
-                Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, rcvr_field)
+                Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src)
             )
         );
 
@@ -453,11 +469,9 @@ fn make_clone_call(
         self.block(vec![statement], TerminatorKind::Call {
             func,
             args: vec![Operand::Move(ref_loc)],
-            destination: Some((loc.clone(), next)),
+            destination: Some((dest, next)),
             cleanup: Some(cleanup),
         }, false);
-
-        loc
     }
 
     fn loop_header(
@@ -500,14 +514,12 @@ fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
         }
     }
 
-    fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
+    fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
         let tcx = self.tcx;
         let span = self.span;
-        let rcvr = Place::Local(Local::new(1+0)).deref();
 
         let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
         let end = self.make_place(Mutability::Not, tcx.types.usize);
-        let ret = self.make_place(Mutability::Mut, tcx.mk_array(ty, len));
 
         // BB #0
         // `let mut beg = 0;`
@@ -537,23 +549,17 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
         self.loop_header(Place::Local(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
 
         // BB #2
-        // `let cloned = Clone::clone(rcvr[beg])`;
+        // `dest[i] = Clone::clone(src[beg])`;
         // Goto #3 if ok, #5 if unwinding happens.
-        let rcvr_field = rcvr.clone().index(beg);
-        let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
+        let dest_field = dest.clone().index(beg);
+        let src_field = src.clone().index(beg);
+        self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3),
+                             BasicBlock::new(5));
 
         // BB #3
-        // `ret[beg] = cloned;`
         // `beg = beg + 1;`
         // `goto #1`;
-        let ret_field = ret.clone().index(beg);
         let statements = vec![
-            self.make_statement(
-                StatementKind::Assign(
-                    ret_field,
-                    Rvalue::Use(Operand::Move(cloned))
-                )
-            ),
             self.make_statement(
                 StatementKind::Assign(
                     Place::Local(beg),
@@ -568,14 +574,8 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
         self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
 
         // BB #4
-        // `return ret;`
-        let ret_statement = self.make_statement(
-            StatementKind::Assign(
-                Place::Local(RETURN_PLACE),
-                Rvalue::Use(Operand::Move(ret.clone())),
-            )
-        );
-        self.block(vec![ret_statement], TerminatorKind::Return, false);
+        // `return dest;`
+        self.block(vec![], TerminatorKind::Return, false);
 
         // BB #5 (cleanup)
         // `let end = beg;`
@@ -600,9 +600,9 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
                          BasicBlock::new(7), BasicBlock::new(9), true);
 
         // BB #7 (cleanup)
-        // `drop(ret[beg])`;
+        // `drop(dest[beg])`;
         self.block(vec![], TerminatorKind::Drop {
-            location: ret.index(beg),
+            location: dest.index(beg),
             target: BasicBlock::new(8),
             unwind: None,
         }, true);
@@ -626,55 +626,50 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
         self.block(vec![], TerminatorKind::Resume, true);
     }
 
-    fn tuple_like_shim(&mut self, tys: &[ty::Ty<'tcx>], kind: AggregateKind<'tcx>) {
-        match kind {
-            AggregateKind::Tuple | AggregateKind::Closure(..) => (),
-            _ => bug!("only tuples and closures are accepted"),
-        };
+    fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>,
+                          src: Place<'tcx>, tys: I)
+            where I: Iterator<Item = ty::Ty<'tcx>> {
+        let mut previous_field = None;
+        for (i, ity) in tys.enumerate() {
+            let field = Field::new(i);
+            let src_field = src.clone().field(field, ity);
 
-        let rcvr = Place::Local(Local::new(1+0)).deref();
+            let dest_field = dest.clone().field(field, ity);
 
-        let mut returns = Vec::new();
-        for (i, ity) in tys.iter().enumerate() {
-            let rcvr_field = rcvr.clone().field(Field::new(i), *ity);
+            // #(2i + 1) is the cleanup block for the previous clone operation
+            let cleanup_block = self.block_index_offset(1);
+            // #(2i + 2) is the next cloning block
+            // (or the Return terminator if this is the last block)
+            let next_block = self.block_index_offset(2);
 
             // BB #(2i)
-            // `returns[i] = Clone::clone(&rcvr.i);`
+            // `dest.i = Clone::clone(&src.i);`
             // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
-            returns.push(
-                self.make_clone_call(
-                    *ity,
-                    rcvr_field,
-                    BasicBlock::new(2 * i + 2),
-                    BasicBlock::new(2 * i + 1),
-                )
+            self.make_clone_call(
+                dest_field.clone(),
+                src_field,
+                ity,
+                next_block,
+                cleanup_block,
             );
 
             // BB #(2i + 1) (cleanup)
-            if i == 0 {
-                // Nothing to drop, just resume.
-                self.block(vec![], TerminatorKind::Resume, true);
-            } else {
+            if let Some((previous_field, previous_cleanup)) = previous_field.take() {
                 // Drop previous field and goto previous cleanup block.
                 self.block(vec![], TerminatorKind::Drop {
-                    location: returns[i - 1].clone(),
-                    target: BasicBlock::new(2 * i - 1),
+                    location: previous_field,
+                    target: previous_cleanup,
                     unwind: None,
                 }, true);
+            } else {
+                // Nothing to drop, just resume.
+                self.block(vec![], TerminatorKind::Resume, true);
             }
+
+            previous_field = Some((dest_field, cleanup_block));
         }
 
-        // `return kind(returns[0], returns[1], ..., returns[tys.len() - 1]);`
-        let ret_statement = self.make_statement(
-            StatementKind::Assign(
-                Place::Local(RETURN_PLACE),
-                Rvalue::Aggregate(
-                    box kind,
-                    returns.into_iter().map(Operand::Move).collect()
-                )
-            )
-        );
-        self.block(vec![ret_statement], TerminatorKind::Return, false);
+        self.block(vec![], TerminatorKind::Return, false);
     }
 }
 
index ebd34f81deb2958dce2985446d95a89b23170d8f..812665f5fa49804d3b2648206e50496bce011977 100644 (file)
@@ -78,7 +78,8 @@
 use transform::{MirPass, MirSource};
 use transform::simplify;
 use transform::no_landing_pads::no_landing_pads;
-use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location};
+use dataflow::{do_dataflow, DebugFormatted, state_for_location};
+use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
 
 pub struct StateTransform;
 
@@ -369,17 +370,33 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 HashMap<BasicBlock, liveness::LocalSet>) {
     let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
     let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
-    let analysis = MaybeStorageLive::new(mir);
+
+    // Calculate when MIR locals have live storage. This gives us an upper bound of their
+    // lifetimes.
+    let storage_live_analysis = MaybeStorageLive::new(mir);
     let storage_live =
-        do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+        do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis,
                     |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
 
+    // Find the MIR locals which do not use StorageLive/StorageDead statements.
+    // The storage of these locals are always live.
     let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
     ignored.visit_mir(mir);
 
-    let mut borrowed_locals = BorrowedLocals(IdxSetBuf::new_empty(mir.local_decls.len()));
-    borrowed_locals.visit_mir(mir);
+    // Calculate the MIR locals which have been previously
+    // borrowed (even if they are still active).
+    // This is only used for immovable generators.
+    let borrowed_locals = if !movable {
+        let analysis = HaveBeenBorrowedLocals::new(mir);
+        let result =
+            do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+                        |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
+        Some((analysis, result))
+    } else {
+        None
+    };
 
+    // Calculate the liveness of MIR locals ignoring borrows.
     let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
     let mut liveness = liveness::liveness_of_locals(mir, LivenessMode {
         include_regular_use: true,
@@ -396,24 +413,41 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 statement_index: data.statements.len(),
             };
 
-            let storage_liveness = state_for_location(loc, &analysis, &storage_live, mir);
+            if let Some((ref analysis, ref result)) = borrowed_locals {
+                let borrowed_locals = state_for_location(loc,
+                                                         analysis,
+                                                         result,
+                                                         mir);
+                // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
+                // This is correct for movable generators since borrows cannot live across
+                // suspension points. However for immovable generators we need to account for
+                // borrows, so we conseratively assume that all borrowed locals live forever.
+                // To do this we just union our `liveness` result with `borrowed_locals`, which
+                // contains all the locals which has been borrowed before this suspension point.
+                // If a borrow is converted to a raw reference, we must also assume that it lives
+                // forever. Note that the final liveness is still bounded by the storage liveness
+                // of the local, which happens using the `intersect` operation below.
+                liveness.outs[block].union(&borrowed_locals);
+            }
+
+            let mut storage_liveness = state_for_location(loc,
+                                                          &storage_live_analysis,
+                                                          &storage_live,
+                                                          mir);
 
+            // Store the storage liveness for later use so we can restore the state
+            // after a suspension point
             storage_liveness_map.insert(block, storage_liveness.clone());
 
-            let mut live_locals = storage_liveness;
-
             // Mark locals without storage statements as always having live storage
-            live_locals.union(&ignored.0);
+            storage_liveness.union(&ignored.0);
 
-            if !movable {
-                // For immovable generators we consider borrowed locals to always be live.
-                // This effectively makes those locals use just the storage liveness.
-                liveness.outs[block].union(&borrowed_locals.0);
-            }
+            // Locals live are live at this point only if they are used across
+            // suspension points (the `liveness` variable)
+            // and their storage is live (the `storage_liveness` variable)
+            storage_liveness.intersect(&liveness.outs[block]);
 
-            // Locals live are live at this point only if they are used across suspension points
-            // and their storage is live
-            live_locals.intersect(&liveness.outs[block]);
+            let live_locals = storage_liveness;
 
             // Add the locals life at this suspension point to the set of locals which live across
             // any suspension points
index 43ee75d1e2ba255b7515530b2cda076464262fdc..ceea97e3ed3b0f1276757873ff053c99e2b295bf 100644 (file)
@@ -19,7 +19,6 @@
 use rustc::mir::*;
 use rustc::mir::visit::*;
 use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::LayoutOf;
 use rustc::ty::subst::{Subst,Substs};
 
 use std::collections::VecDeque;
@@ -655,7 +654,7 @@ fn create_temp_if_necessary(
 fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           param_env: ty::ParamEnv<'tcx>,
                           ty: Ty<'tcx>) -> Option<u64> {
-    (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
+    tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
 }
 
 fn subst_and_normalize<'a, 'tcx: 'a>(
index b896e6ca85343d0460d18ff45df868b7949ea769..da76adfd48f3ffd4306317d4579c7fc120c2c63f 100644 (file)
@@ -737,7 +737,7 @@ fn visit_terminator_kind(&mut self,
                     Abi::PlatformIntrinsic => {
                         assert!(!self.tcx.is_const_fn(def_id));
                         match &self.tcx.item_name(def_id)[..] {
-                            "size_of" | "min_align_of" => is_const_fn = Some(def_id),
+                            "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id),
 
                             name if name.starts_with("simd_shuffle") => {
                                 is_shuffle = true;
index c23f28fe2205f943d4cfec7fc727d1993141dc13..008c71cc9ce3d2129a892f08753ff1c4e2eb8faa 100644 (file)
@@ -119,6 +119,11 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
                                              kind.name())
                                 .span_label(e.span,
                                             "can only break with a value inside `loop`")
+                                .span_suggestion(e.span,
+                                                 &format!("instead, use `break` on its own \
+                                                           without a value inside this `{}` loop",
+                                                          kind.name()),
+                                                 "break".to_string())
                                 .emit();
                         }
                     }
index 2e494fdfad8b894bee857ce1be51491e6076dbba..841350bdb68e117d1e2c5ec7d9ea58a9bfb85ff4 100644 (file)
@@ -791,7 +791,7 @@ pub fn get_field_ref_data(
         field_ref: &ast::Field,
         variant: &ty::VariantDef,
     ) -> Option<Ref> {
-        let f = variant.field_named(field_ref.ident.node.name);
+        let f = variant.find_field_named(field_ref.ident.node.name)?;
         // We don't really need a sub-span here, but no harm done
         let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
         filter!(self.span_utils, sub_span, field_ref.ident.span, None);
@@ -870,6 +870,17 @@ fn docs_for_attrs(&self, attrs: &[Attribute]) -> String {
                         result.push_str(&val.as_str());
                     }
                     result.push('\n');
+                } else if let Some(meta_list) = attr.meta_item_list() {
+                    meta_list.into_iter()
+                             .filter(|it| it.check_name("include"))
+                             .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
+                             .flat_map(|it| it)
+                             .filter(|meta| meta.check_name("contents"))
+                             .filter_map(|meta| meta.value_str())
+                             .for_each(|val| {
+                                 result.push_str(&val.as_str());
+                                 result.push('\n');
+                             });
                 }
             }
         }
index 8afa63a5e9735e113bceac783870cdca3d54d91f..ded9a296817b3f85dd8cd80da98de7d132b86787 100644 (file)
@@ -759,7 +759,10 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
 
         if asm2wasm && config.emit_obj {
             let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
-            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
+            let suffix = ".wasm.map"; // FIXME use target suffix
+            let map = cgcx.output_filenames.path(OutputType::Exe)
+                .with_extension(&suffix[1..]);
+            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
             timeline.record("binaryen");
 
             if !config.emit_asm {
@@ -814,7 +817,8 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
 fn binaryen_assemble(cgcx: &CodegenContext,
                      handler: &Handler,
                      assembly: &Path,
-                     object: &Path) {
+                     object: &Path,
+                     map: &Path) {
     use rustc_binaryen::{Module, ModuleOptions};
 
     let input = fs::read(&assembly).and_then(|contents| {
@@ -823,10 +827,10 @@ fn binaryen_assemble(cgcx: &CodegenContext,
     let mut options = ModuleOptions::new();
     if cgcx.debuginfo != config::NoDebugInfo {
         options.debuginfo(true);
+        let map_file_name = map.file_name().unwrap();
+        options.source_map_url(map_file_name.to_str().unwrap());
     }
-    if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
-        options.start("main");
-    }
+
     options.stack(1024 * 1024);
     options.import_memory(cgcx.wasm_import_memory);
     let assembled = input.and_then(|input| {
@@ -834,7 +838,13 @@ fn binaryen_assemble(cgcx: &CodegenContext,
             .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
     });
     let err = assembled.and_then(|binary| {
-        fs::write(&object, binary.data())
+        fs::write(&object, binary.data()).and_then(|()| {
+            if cgcx.debuginfo != config::NoDebugInfo {
+                fs::write(map, binary.source_map())
+            } else {
+                Ok(())
+            }
+        })
     });
     if let Err(e) = err {
         handler.err(&format!("failed to run binaryen assembler: {}", e));
@@ -1452,7 +1462,7 @@ fn start_executing_work(tcx: TyCtxt,
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
         binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
         debuginfo: tcx.sess.opts.debuginfo,
-        wasm_import_memory: wasm_import_memory,
+        wasm_import_memory,
         assembler_cmd,
     };
 
index 06b8d9ff7b306d1e8ae9eacfb1662baa72e90d08..a285e5f263ab7037b3f0df4045203f6a89ab639b 100644 (file)
@@ -464,8 +464,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a CodegenCx<'a, 'tcx> {
     type TyLayout = TyLayout<'tcx>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        (self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
-            .layout_of(ty)
+        self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty))
             .unwrap_or_else(|e| match e {
                 LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
                 _ => bug!("failed to get layout for `{}`: {}", ty, e)
index a3e55205dd8759c46f5cca3075e78e990e612311..cd1975488a24a3f201d9ece1574685592f2d3ce5 100644 (file)
@@ -411,6 +411,11 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
                                         self.cx.align_of(substs.type_at(0)).abi());
                                     Ok(Const::new(llval, tcx.types.usize))
                                 }
+                                "type_id" => {
+                                    let llval = C_u64(self.cx,
+                                        self.cx.tcx.type_id_hash(substs.type_at(0)));
+                                    Ok(Const::new(llval, tcx.types.u64))
+                                }
                                 _ => span_bug!(span, "{:?} in constant", terminator.kind)
                             }
                         } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
index 570eecfc267deea3ff5fa8f7fe7dc044c5bfc141..4c10f28eb8e5de23d9987a82c087f716adf4f92c 100644 (file)
@@ -40,6 +40,8 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("compare_impl_method(impl_trait_ref={:?})",
            impl_trait_ref);
 
+    let impl_m_span = tcx.sess.codemap().def_span(impl_m_span);
+
     if let Err(ErrorReported) = compare_self_type(tcx,
                                                   impl_m,
                                                   impl_m_span,
@@ -186,6 +188,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     check_region_bounds_on_impl_method(tcx,
                                        impl_m_span,
                                        impl_m,
+                                       trait_m,
                                        &trait_m_generics,
                                        &impl_m_generics,
                                        trait_to_skol_substs)?;
@@ -310,7 +313,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             };
 
             let mut diag = struct_span_err!(tcx.sess,
-                                            cause.span,
+                                            cause.span(&tcx),
                                             E0053,
                                             "method `{}` has an incompatible type for trait",
                                             trait_m.name);
@@ -346,10 +349,12 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 span: Span,
                                                 impl_m: &ty::AssociatedItem,
+                                                trait_m: &ty::AssociatedItem,
                                                 trait_generics: &ty::Generics,
                                                 impl_generics: &ty::Generics,
                                                 trait_to_skol_substs: &Substs<'tcx>)
                                                 -> Result<(), ErrorReported> {
+    let span = tcx.sess.codemap().def_span(span);
     let trait_params = &trait_generics.regions[..];
     let impl_params = &impl_generics.regions[..];
 
@@ -371,14 +376,18 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // are zero. Since I don't quite know how to phrase things at
     // the moment, give a kind of vague error message.
     if trait_params.len() != impl_params.len() {
-        struct_span_err!(tcx.sess,
-                         span,
-                         E0195,
-                         "lifetime parameters or bounds on method `{}` do not match the \
-                          trait declaration",
-                         impl_m.name)
-            .span_label(span, "lifetimes do not match trait")
-            .emit();
+        let mut err = struct_span_err!(tcx.sess,
+                                       span,
+                                       E0195,
+                                       "lifetime parameters or bounds on method `{}` do not match \
+                                        the trait declaration",
+                                       impl_m.name);
+        err.span_label(span, "lifetimes do not match method in trait");
+        if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) {
+            err.span_label(tcx.sess.codemap().def_span(sp),
+                           "lifetimes in impl do not match this method in trait");
+        }
+        err.emit();
         return Err(ErrorReported);
     }
 
@@ -424,9 +433,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                 }).map(|(ref impl_arg, ref trait_arg)| {
                     (impl_arg.span, Some(trait_arg.span))
                 })
-                .unwrap_or_else(|| (cause.span, tcx.hir.span_if_local(trait_m.def_id)))
+                .unwrap_or_else(|| (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)))
             } else {
-                (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+                (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
             }
         }
         TypeError::Sorts(ExpectedFound { .. }) => {
@@ -459,14 +468,14 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                              {
                                  (impl_m_output.span(), Some(trait_m_output.span()))
                              } else {
-                                 (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+                                 (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
                              }
                          })
             } else {
-                (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+                (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
             }
         }
-        _ => (cause.span, tcx.hir.span_if_local(trait_m.def_id)),
+        _ => (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)),
     }
 }
 
index 781eeaef2482cca189ca56db038b243f01a1f666..2e45e3b1f3521db331ef2d9fc537bbd6e0dba346 100644 (file)
@@ -150,15 +150,15 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     fn visit_pat(&mut self, pat: &'tcx Pat) {
+        intravisit::walk_pat(self, pat);
+
+        self.expr_count += 1;
+
         if let PatKind::Binding(..) = pat.node {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
             let ty = self.fcx.tables.borrow().pat_ty(pat);
             self.record(ty, Some(scope), None, pat.span);
         }
-
-        self.expr_count += 1;
-
-        intravisit::walk_pat(self, pat);
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
index 483dd345286d433601cdd3d2728b73ee6ff5865a..363d4a9dc0cd3eb5ff388df588b28a9fcba6b4d5 100644 (file)
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
-use rustc::ty::layout::LayoutOf;
 use errors::{DiagnosticBuilder, DiagnosticId};
 
 use require_c_abi_if_variadic;
@@ -1015,7 +1014,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let span = body.value.span;
 
     if body.is_generator && can_be_generator.is_some() {
-        fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)));
+        let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+        fcx.yield_ty = Some(yield_ty);
     }
 
     GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
@@ -1551,7 +1552,7 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
     let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| {
         let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
-        let layout = (tcx, param_env).layout_of(ty);
+        let layout = tcx.layout_of(param_env.and(ty));
         // We are currently checking the type this field came from, so it must be local
         let span = tcx.hir.span_if_local(field.did).unwrap();
         let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
index 07d5f813cbbce76977700c569af80bdd868a8ea3..88a2dc817ae63f139f1ad1a38bee016c777fa732 100644 (file)
@@ -82,29 +82,37 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| {
-                    if let Some(overlap) =
-                        traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
-                                                  IntercrateMode::Issue43355)
-                    {
+                let used_to_be_allowed = traits::overlapping_impls(
+                    self.tcx,
+                    impl1_def_id,
+                    impl2_def_id,
+                    IntercrateMode::Issue43355,
+                    |overlap| {
                         self.check_for_common_items_in_impls(
-                            impl1_def_id, impl2_def_id, overlap, false);
+                            impl1_def_id,
+                            impl2_def_id,
+                            overlap,
+                            false,
+                        );
                         false
-                    } else {
-                        true
-                    }
-                });
+                    },
+                    || true,
+                );
 
                 if used_to_be_allowed {
-                    self.tcx.infer_ctxt().enter(|infcx| {
-                        if let Some(overlap) =
-                            traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
-                                                      IntercrateMode::Fixed)
-                        {
-                            self.check_for_common_items_in_impls(
-                                impl1_def_id, impl2_def_id, overlap, true);
-                        }
-                    });
+                    traits::overlapping_impls(
+                        self.tcx,
+                        impl1_def_id,
+                        impl2_def_id,
+                        IntercrateMode::Fixed,
+                        |overlap| self.check_for_common_items_in_impls(
+                            impl1_def_id,
+                            impl2_def_id,
+                            overlap,
+                            true,
+                        ),
+                        || (),
+                    );
                 }
             }
         }
index 0929b833c1965395337753946980f8f4db38ec84..7c9a49c82a9395b186eab37471140cd64c368ab6 100644 (file)
@@ -2447,7 +2447,12 @@ fn clean(&self, cx: &DocContext) -> Type {
                 let def_id = cx.tcx.hir.body_owner_def_id(n);
                 let param_env = cx.tcx.param_env(def_id);
                 let substs = Substs::identity_for_item(cx.tcx, def_id);
-                let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap();
+                let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| {
+                    cx.tcx.mk_const(ty::Const {
+                        val: ConstVal::Unevaluated(def_id, substs),
+                        ty: cx.tcx.types.usize
+                    })
+                });
                 let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
                     n.to_string()
                 } else if let ConstVal::Unevaluated(def_id, _) = n.val {
@@ -2577,7 +2582,9 @@ fn clean(&self, cx: &DocContext) -> Type {
                 let mut n = cx.tcx.lift(&n).unwrap();
                 if let ConstVal::Unevaluated(def_id, substs) = n.val {
                     let param_env = cx.tcx.param_env(def_id);
-                    n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap()
+                    if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) {
+                        n = new_n;
+                    }
                 };
                 let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
                     n.to_string()
index 0f9e7001c159bf545f6dee5cb9083d94ce124bfe..ba9bcb7af7ae0e8c0e9e4612e4f17abbc9e25b34 100644 (file)
@@ -47,6 +47,8 @@
     // 2 for "In Return Types"
     var currentTab = 0;
 
+    var themesWidth = null;
+
     function hasClass(elem, className) {
         if (elem && className && elem.className) {
             var elemClass = elem.className;
                 sidebar.appendChild(div);
             }
         }
+        var themeChoices = document.getElementById("theme-choices");
+        if (themeChoices) {
+            if (!themesWidth) {
+                var savedState = themeChoices.style.display;
+                themeChoices.style.display = 'block';
+                themesWidth = themeChoices.offsetWidth + 'px';
+                themeChoices.style.display = savedState;
+            }
+            themeChoices.style.position = "fixed";
+            themeChoices.style.width = themesWidth;
+            themeChoices.style.top = '78px';
+            themeChoices.style.left = '250px';
+        }
         document.getElementsByTagName("body")[0].style.marginTop = '45px';
         var themePicker = document.getElementById("theme-picker");
         if (themePicker) {
             themePicker.style.position = "fixed";
+            themePicker.style.top = "50px";
+            themePicker.style.left = "250px";
         }
     }
 
         var themePicker = document.getElementById("theme-picker");
         if (themePicker) {
             themePicker.style.position = "absolute";
+            themePicker.style.top = null;
+            themePicker.style.left = null;
+        }
+        var themeChoices = document.getElementById("theme-choices");
+        if (themeChoices) {
+            themeChoices.style.position = 'absolute';
+            themeChoices.style.width = null;
+            themeChoices.style.top = null;
+            themeChoices.style.left = null;
         }
     }
 
index d2eeb2e15b3ddbfedb492999eb56113451c9c2bf..53d57b672303e4ac91e1db5c0b7229767532eea5 100644 (file)
@@ -181,15 +181,19 @@ nav.sub {
        overflow: auto;
 }
 
-.sidebar .current {
+.sidebar .block > ul > li {
        margin-right: -20px;
 }
 
-.content, nav { max-width: 960px; }
+.content, nav {
+       max-width: 960px;
+}
 
 /* Everything else */
 
-.js-only, .hidden { display: none !important; }
+.js-only, .hidden {
+       display: none !important;
+}
 
 .sidebar img {
        margin: 20px auto;
@@ -218,7 +222,9 @@ nav.sub {
        border: none;
 }
 
-.location a:first-child { font-weight: 500; }
+.location a:first-child {
+       font-weight: 500;
+}
 
 .block {
        padding: 0;
@@ -299,7 +305,9 @@ nav.sub {
        -ms-user-select: none;
        user-select: none;
 }
-.line-numbers span { cursor: pointer; }
+.line-numbers span {
+       cursor: pointer;
+}
 
 .docblock-short p {
        display: inline;
@@ -317,7 +325,9 @@ nav.sub {
        text-overflow: ellipsis;
        margin: 0;
 }
-.docblock-short code { white-space: nowrap; }
+.docblock-short code {
+       white-space: nowrap;
+}
 
 .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
        border-bottom: 1px solid;
@@ -384,7 +394,9 @@ h4 > code, h3 > code, .invisible > code {
        display: inline-block;
 }
 
-#main { position: relative; }
+#main {
+       position: relative;
+}
 #main > .since {
        top: inherit;
        font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@@ -428,7 +440,9 @@ h4 > code, h3 > code, .invisible > code {
        padding: 0;
 }
 
-.content .item-list li { margin-bottom: 1em; }
+.content .item-list li {
+       margin-bottom: 1em;
+}
 
 .content .multi-column {
        -moz-column-count: 5;
@@ -856,6 +870,7 @@ span.since {
                display: block;
                border-bottom: 1px solid;
                border-right: 1px solid;
+               height: 45px;
        }
 
        .sidebar-elems {
@@ -875,13 +890,19 @@ span.since {
        }
 
        nav.sub {
-               margin: 0 auto;
+               width: calc(100% - 32px);
+               float: right;
        }
 
        .content {
                margin-left: 0px;
        }
 
+       #main {
+               margin-top: 50px;
+               padding: 0;
+       }
+
        .content .in-band {
                width: 100%;
        }
@@ -1028,6 +1049,24 @@ h4 > .important-traits {
 
        .show-it {
                display: block;
+               width: 246px;
+       }
+
+       .show-it > .block.items {
+               margin: 8px 0;
+       }
+
+       .show-it > .block.items > ul {
+               margin: 0;
+       }
+
+       .show-it > .block.items > ul > li {
+               text-align: center;
+               margin: 2px 0;
+       }
+
+       .show-it > .block.items > ul > li > a {
+               font-size: 21px;
        }
 
        /* Because of ios, we need to actually have a full height sidebar title so the
@@ -1184,8 +1223,8 @@ kbd {
 
 @media (max-width: 700px) {
        .theme-picker {
-               left: 109px;
-               top: 7px;
+               left: 10px;
+               top: 54px;
                z-index: 1;
        }
 }
index 4c6bcab72b7c9b5a4803bff18eadf1d5fd9be429..907a6e4fcb4a0d9dc48f0550bf1589b3a5bdad16 100644 (file)
@@ -383,6 +383,6 @@ kbd {
 
 @media (max-width: 700px) {
        #theme-picker {
-               background: #353535;
+               background: #f0f0f0;
        }
 }
index 3430ecabcbeaea079874ef3406e77c19491ac5aa..c1fe4a89d6ac0f9a750a49727cab3be1c4514321 100644 (file)
@@ -48,3 +48,4 @@ jemalloc = ["alloc_jemalloc"]
 force_alloc_system = []
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
+wasm_syscall = []
index 9810dede61821e03c80c3405e7f32b2c28744146..ecf68f29d6f1f7c80c4324d1c71073b09a8a019c 100644 (file)
@@ -1531,6 +1531,7 @@ fn test_to_degrees() {
         assert!(nan.to_degrees().is_nan());
         assert_eq!(inf.to_degrees(), inf);
         assert_eq!(neg_inf.to_degrees(), neg_inf);
+        assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
     }
 
     #[test]
index a19fe825f21fa06344710ac9de67e2b33a371137..e91d3a32a50cd80f232c580c934189901e22bf16 100644 (file)
@@ -1026,9 +1026,9 @@ pub fn as_ptr(&self) -> *const c_char {
     /// The returned slice will **not** contain the trailing nul terminator that this C
     /// string has.
     ///
-    /// > **Note**: This method is currently implemented as a 0-cost cast, but
-    /// > it is planned to alter its definition in the future to perform the
-    /// > length calculation whenever this method is called.
+    /// > **Note**: This method is currently implemented as a constant-time
+    /// > cast, but it is planned to alter its definition in the future to
+    /// > perform the length calculation whenever this method is called.
     ///
     /// # Examples
     ///
@@ -1077,9 +1077,9 @@ pub fn to_bytes_with_nul(&self) -> &[u8] {
     /// it will return an error with details of where UTF-8 validation failed.
     ///
     /// > **Note**: This method is currently implemented to check for validity
-    /// > after a 0-cost cast, but it is planned to alter its definition in the
-    /// > future to perform the length calculation in addition to the UTF-8
-    /// > check whenever this method is called.
+    /// > after a constant-time cast, but it is planned to alter its definition
+    /// > in the future to perform the length calculation in addition to the
+    /// > UTF-8 check whenever this method is called.
     ///
     /// [`&str`]: ../primitive.str.html
     ///
@@ -1110,9 +1110,9 @@ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
     /// with the result.
     ///
     /// > **Note**: This method is currently implemented to check for validity
-    /// > after a 0-cost cast, but it is planned to alter its definition in the
-    /// > future to perform the length calculation in addition to the UTF-8
-    /// > check whenever this method is called.
+    /// > after a constant-time cast, but it is planned to alter its definition
+    /// > in the future to perform the length calculation in addition to the
+    /// > UTF-8 check whenever this method is called.
     ///
     /// [`Cow`]: ../borrow/enum.Cow.html
     /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
index d1f3ccbd2c6e041de5c08b02bea5ea52c9e4324c..5cea389531f94bd5c2e34c77d02eb5c246fbff8b 100644 (file)
@@ -482,20 +482,42 @@ pub fn metadata(&self) -> io::Result<Metadata> {
         self.inner.file_attr().map(Metadata)
     }
 
-    /// Creates a new independently owned handle to the underlying file.
-    ///
-    /// The returned `File` is a reference to the same state that this object
-    /// references. Both handles will read and write with the same cursor
-    /// position.
+    /// Create a new `File` instance that shares the same underlying file handle
+    /// as the existing `File` instance. Reads, writes, and seeks will affect
+    /// both `File` instances simultaneously.
     ///
     /// # Examples
     ///
+    /// Create two handles for a file named `foo.txt`:
+    ///
     /// ```no_run
     /// use std::fs::File;
     ///
     /// # fn foo() -> std::io::Result<()> {
-    /// let mut f = File::open("foo.txt")?;
-    /// let file_copy = f.try_clone()?;
+    /// let mut file = File::open("foo.txt")?;
+    /// let file_copy = file.try_clone()?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create
+    /// two handles, seek one of them, and read the remaining bytes from the
+    /// other handle:
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::SeekFrom;
+    /// use std::io::prelude::*;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let mut file = File::open("foo.txt")?;
+    /// let mut file_copy = file.try_clone()?;
+    ///
+    /// file.seek(SeekFrom::Start(3))?;
+    ///
+    /// let mut contents = vec![];
+    /// file_copy.read_to_end(&mut contents)?;
+    /// assert_eq!(contents, b"def\n");
     /// # Ok(())
     /// # }
     /// ```
@@ -1001,7 +1023,7 @@ pub fn accessed(&self) -> io::Result<SystemTime> {
         self.0.accessed().map(FromInner::from_inner)
     }
 
-    /// Returns the creation time listed in the this metadata.
+    /// Returns the creation time listed in this metadata.
     ///
     /// The returned value corresponds to the `birthtime` field of `stat` on
     /// Unix platforms and the `ftCreationTime` field on Windows platforms.
index a8049e676b3bb6a00f39823c7691bff3dfc23e0a..642fa8775a479d8a74f522a923beb734c85787e7 100644 (file)
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
+#![feature(external_doc)]
 #![feature(fs_read_write)]
 #![feature(fixed_size_array)]
 #![feature(float_from_str_radix)]
diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs
deleted file mode 100644 (file)
index 279caf8..0000000
+++ /dev/null
@@ -1,107 +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.
-
-//! Raw OS-specific types for the current platform/architecture
-
-#![stable(feature = "raw_os", since = "1.1.0")]
-
-use fmt;
-
-#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
-                                       target_arch = "arm",
-                                       target_arch = "powerpc",
-                                       target_arch = "powerpc64",
-                                       target_arch = "s390x")),
-          all(target_os = "android", any(target_arch = "aarch64",
-                                         target_arch = "arm")),
-          all(target_os = "l4re", target_arch = "x86_64"),
-          all(target_os = "openbsd", target_arch = "aarch64"),
-          all(target_os = "fuchsia", target_arch = "aarch64")))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
-#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
-                                           target_arch = "arm",
-                                           target_arch = "powerpc",
-                                           target_arch = "powerpc64",
-                                           target_arch = "s390x")),
-              all(target_os = "android", any(target_arch = "aarch64",
-                                             target_arch = "arm")),
-              all(target_os = "l4re", target_arch = "x86_64"),
-              all(target_os = "openbsd", target_arch = "aarch64"),
-              all(target_os = "fuchsia", target_arch = "aarch64"))))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
-
-/// Type used to construct void pointers for use with C.
-///
-/// This type is only useful as a pointer target. Do not use it as a
-/// return type for FFI functions which have the `void` return type in
-/// C. Use the unit type `()` or omit the return type instead.
-// NB: For LLVM to recognize the void pointer type and by extension
-//     functions like malloc(), we need to have it represented as i8* in
-//     LLVM bitcode. The enum used here ensures this and prevents misuse
-//     of the "raw" type by only having private variants.. We need two
-//     variants, because the compiler complains about the repr attribute
-//     otherwise.
-#[repr(u8)]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub enum c_void {
-    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
-               issue = "0")]
-    #[doc(hidden)] __variant1,
-    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
-               issue = "0")]
-    #[doc(hidden)] __variant2,
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for c_void {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad("c_void")
-    }
-}
-
-#[cfg(test)]
-#[allow(unused_imports)]
-mod tests {
-    use any::TypeId;
-    use libc;
-    use mem;
-
-    macro_rules! ok {
-        ($($t:ident)*) => {$(
-            assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
-                    "{} is wrong", stringify!($t));
-        )*}
-    }
-
-    #[test]
-    fn same() {
-        use os::raw;
-        ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
-            c_longlong c_ulonglong c_float c_double);
-    }
-}
diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md
new file mode 100644 (file)
index 0000000..9a55767
--- /dev/null
@@ -0,0 +1,11 @@
+Equivalent to C's `char` type.
+
+[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long.
+
+C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information.
+
+[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types
+[Rust's `char` type]: ../../primitive.char.html
+[`CStr`]: ../../ffi/struct.CStr.html
+[`i8`]: ../../primitive.i8.html
+[`u8`]: ../../primitive.u8.html
diff --git a/src/libstd/os/raw/double.md b/src/libstd/os/raw/double.md
new file mode 100644 (file)
index 0000000..6818dad
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `double` type.
+
+This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
+
+[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`float`]: type.c_float.html
+[`f64`]: ../../primitive.f64.html
diff --git a/src/libstd/os/raw/float.md b/src/libstd/os/raw/float.md
new file mode 100644 (file)
index 0000000..57d1071
--- /dev/null
@@ -0,0 +1,6 @@
+Equivalent to C's `float` type.
+
+This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
+
+[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`f32`]: ../../primitive.f32.html
diff --git a/src/libstd/os/raw/int.md b/src/libstd/os/raw/int.md
new file mode 100644 (file)
index 0000000..a0d25fd
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `signed int` (`int`) type.
+
+This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example.
+
+[`short`]: type.c_short.html
+[`i32`]: ../../primitive.i32.html
+[`i16`]: ../../primitive.i16.html
diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md
new file mode 100644 (file)
index 0000000..c620b40
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `signed long` (`long`) type.
+
+This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`.
+
+[`int`]: type.c_int.html
+[`i32`]: ../../primitive.i32.html
+[`i64`]: ../../primitive.i64.html
diff --git a/src/libstd/os/raw/longlong.md b/src/libstd/os/raw/longlong.md
new file mode 100644 (file)
index 0000000..ab3d643
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `signed long long` (`long long`) type.
+
+This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type.
+
+[`long`]: type.c_int.html
+[`i64`]: ../../primitive.i64.html
+[`i128`]: ../../primitive.i128.html
diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs
new file mode 100644 (file)
index 0000000..d5eeb52
--- /dev/null
@@ -0,0 +1,135 @@
+// 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.
+
+//! Platform-specific types, as defined by C.
+//!
+//! Code that interacts via FFI will almost certainly be using the
+//! base types provided by C, which aren't nearly as nicely defined
+//! as Rust's primitive types. This module provides types which will
+//! match those defined by C, so that code that interacts with C will
+//! refer to the correct types.
+
+#![stable(feature = "raw_os", since = "1.1.0")]
+
+use fmt;
+
+#[doc(include = "os/raw/char.md")]
+#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
+                                       target_arch = "arm",
+                                       target_arch = "powerpc",
+                                       target_arch = "powerpc64",
+                                       target_arch = "s390x")),
+          all(target_os = "android", any(target_arch = "aarch64",
+                                         target_arch = "arm")),
+          all(target_os = "l4re", target_arch = "x86_64"),
+          all(target_os = "openbsd", target_arch = "aarch64"),
+          all(target_os = "fuchsia", target_arch = "aarch64")))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
+#[doc(include = "os/raw/char.md")]
+#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
+                                           target_arch = "arm",
+                                           target_arch = "powerpc",
+                                           target_arch = "powerpc64",
+                                           target_arch = "s390x")),
+              all(target_os = "android", any(target_arch = "aarch64",
+                                             target_arch = "arm")),
+              all(target_os = "l4re", target_arch = "x86_64"),
+              all(target_os = "openbsd", target_arch = "aarch64"),
+              all(target_os = "fuchsia", target_arch = "aarch64"))))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
+#[doc(include = "os/raw/schar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
+#[doc(include = "os/raw/uchar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
+#[doc(include = "os/raw/short.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
+#[doc(include = "os/raw/ushort.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
+#[doc(include = "os/raw/int.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
+#[doc(include = "os/raw/uint.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
+#[doc(include = "os/raw/longlong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
+#[doc(include = "os/raw/ulonglong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
+#[doc(include = "os/raw/float.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
+#[doc(include = "os/raw/double.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
+
+/// Equivalent to C's `void` type when used as a [pointer].
+///
+/// In essence, `*const c_void` is equivalent to C's `const void*`
+/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
+/// *not* the same as C's `void` return type, which is Rust's `()` type.
+///
+/// Ideally, this type would be equivalent to [`!`], but currently it may
+/// be more ideal to use `c_void` for FFI purposes.
+///
+/// [`!`]: ../../primitive.never.html
+/// [pointer]: ../../primitive.pointer.html
+// NB: For LLVM to recognize the void pointer type and by extension
+//     functions like malloc(), we need to have it represented as i8* in
+//     LLVM bitcode. The enum used here ensures this and prevents misuse
+//     of the "raw" type by only having private variants.. We need two
+//     variants, because the compiler complains about the repr attribute
+//     otherwise.
+#[repr(u8)]
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub enum c_void {
+    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+               issue = "0")]
+    #[doc(hidden)] __variant1,
+    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+               issue = "0")]
+    #[doc(hidden)] __variant2,
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for c_void {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("c_void")
+    }
+}
+
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests {
+    use any::TypeId;
+    use libc;
+    use mem;
+
+    macro_rules! ok {
+        ($($t:ident)*) => {$(
+            assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+                    "{} is wrong", stringify!($t));
+        )*}
+    }
+
+    #[test]
+    fn same() {
+        use os::raw;
+        ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+            c_longlong c_ulonglong c_float c_double);
+    }
+}
diff --git a/src/libstd/os/raw/schar.md b/src/libstd/os/raw/schar.md
new file mode 100644 (file)
index 0000000..6aa8b12
--- /dev/null
@@ -0,0 +1,6 @@
+Equivalent to C's `signed char` type.
+
+This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`i8`]: ../../primitive.i8.html
diff --git a/src/libstd/os/raw/short.md b/src/libstd/os/raw/short.md
new file mode 100644 (file)
index 0000000..be92c6c
--- /dev/null
@@ -0,0 +1,6 @@
+Equivalent to C's `signed short` (`short`) type.
+
+This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example.
+
+[`char`]: type.c_char.html
+[`i16`]: ../../primitive.i16.html
diff --git a/src/libstd/os/raw/uchar.md b/src/libstd/os/raw/uchar.md
new file mode 100644 (file)
index 0000000..b6ca711
--- /dev/null
@@ -0,0 +1,6 @@
+Equivalent to C's `unsigned char` type.
+
+This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`u8`]: ../../primitive.u8.html
diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md
new file mode 100644 (file)
index 0000000..6f7013a
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned int` type.
+
+This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example.
+
+[`int`]: type.c_int.html
+[`u32`]: ../../primitive.u32.html
+[`u16`]: ../../primitive.u16.html
diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md
new file mode 100644 (file)
index 0000000..c350395
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned long` type.
+
+This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`.
+
+[`long`]: type.c_long.html
+[`u32`]: ../../primitive.u32.html
+[`u64`]: ../../primitive.u64.html
diff --git a/src/libstd/os/raw/ulonglong.md b/src/libstd/os/raw/ulonglong.md
new file mode 100644 (file)
index 0000000..c41faf7
--- /dev/null
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned long long` type.
+
+This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type.
+
+[`long long`]: type.c_longlong.html
+[`u64`]: ../../primitive.u64.html
+[`u128`]: ../../primitive.u128.html
diff --git a/src/libstd/os/raw/ushort.md b/src/libstd/os/raw/ushort.md
new file mode 100644 (file)
index 0000000..d364abb
--- /dev/null
@@ -0,0 +1,6 @@
+Equivalent to C's `unsigned short` type.
+
+This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`].
+
+[`short`]: type.c_short.html
+[`u16`]: ../../primitive.u16.html
index 560876006d3f348999cb6568a1381306d7bbc39c..112e110609310081a080748ca5e4ea23286de3f3 100644 (file)
@@ -198,7 +198,7 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
 #[unstable(feature = "ptr_internals", issue = "0")]
 impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: ?Sized> UnwindSafe for Mutex<T> {}
index c980ae75261caad971960e712a5259ba0da5cb96..78a3b82546e3a93258d753b810c6846f45ad1da9 100644 (file)
@@ -111,10 +111,11 @@ fn drop(&mut self) {
 
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
         None
     }
-    pub unsafe fn init() -> Option<usize> {
+    pub unsafe fn init() -> Option<Guard> {
         None
     }
 }
index c4aad8d86f8b1f5e4b6fba452c4eb64e9476cf6d..c4719a94c7e9dfa15252e216af2180c62b886a14 100644 (file)
@@ -88,6 +88,7 @@ pub fn into_id(self) -> usize {
 }
 
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
 }
index 51adbc24ae04779ed6eaba4f2ec7c6014bf2989e..40453f9b8a15b4e1dcdb2ddf64bb18332f33a734 100644 (file)
@@ -57,9 +57,6 @@ mod imp {
     use sys_common::thread_info;
 
 
-    // This is initialized in init() and only read from after
-    static mut PAGE_SIZE: usize = 0;
-
     #[cfg(any(target_os = "linux", target_os = "android"))]
     unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
         #[repr(C)]
@@ -102,12 +99,12 @@ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
                                     _data: *mut libc::c_void) {
         use sys_common::util::report_overflow;
 
-        let guard = thread_info::stack_guard().unwrap_or(0);
+        let guard = thread_info::stack_guard().unwrap_or(0..0);
         let addr = siginfo_si_addr(info);
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
-        if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
+        if guard.start <= addr && addr < guard.end {
             report_overflow();
             rtabort!("stack overflow");
         } else {
@@ -123,8 +120,6 @@ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
     static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
 
     pub unsafe fn init() {
-        PAGE_SIZE = ::sys::os::page_size();
-
         let mut action: sigaction = mem::zeroed();
         action.sa_flags = SA_SIGINFO | SA_ONSTACK;
         action.sa_sigaction = signal_handler as sighandler_t;
index 525882c1e1ebb8134973b2c989474a0242da40e9..72cdb9440b8e7e3bdae6a51ebf554f0268dbdf10 100644 (file)
@@ -205,8 +205,10 @@ fn drop(&mut self) {
           not(target_os = "solaris")))]
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    use ops::Range;
+    pub type Guard = Range<usize>;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
 }
 
 
@@ -222,14 +224,43 @@ pub mod guard {
     use libc;
     use libc::mmap;
     use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+    use ops::Range;
     use sys::os;
 
-    #[cfg(any(target_os = "macos",
-              target_os = "bitrig",
-              target_os = "openbsd",
-              target_os = "solaris"))]
+    // This is initialized in init() and only read from after
+    static mut PAGE_SIZE: usize = 0;
+
+    pub type Guard = Range<usize>;
+
+    #[cfg(target_os = "solaris")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = ::mem::zeroed();
+        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+        Some(current_stack.ss_sp)
+    }
+
+    #[cfg(target_os = "macos")]
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        current().map(|s| s as *mut libc::c_void)
+        let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+             libc::pthread_get_stacksize_np(libc::pthread_self());
+        Some(stackaddr as *mut libc::c_void)
+    }
+
+    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = ::mem::zeroed();
+        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
+                                             &mut current_stack), 0);
+
+        let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
+        let stackaddr = if libc::pthread_main_np() == 1 {
+            // main thread
+            current_stack.ss_sp as usize - current_stack.ss_size + extra
+        } else {
+            // new thread
+            current_stack.ss_sp as usize - current_stack.ss_size
+        };
+        Some(stackaddr as *mut libc::c_void)
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
@@ -253,8 +284,9 @@ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
         ret
     }
 
-    pub unsafe fn init() -> Option<usize> {
-        let psize = os::page_size();
+    pub unsafe fn init() -> Option<Guard> {
+        PAGE_SIZE = os::page_size();
+
         let mut stackaddr = get_stack_start()?;
 
         // Ensure stackaddr is page aligned! A parent process might
@@ -263,9 +295,9 @@ pub unsafe fn init() -> Option<usize> {
         // stackaddr < stackaddr + stacksize, so if stackaddr is not
         // page-aligned, calculate the fix such that stackaddr <
         // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = (stackaddr as usize) % psize;
+        let remainder = (stackaddr as usize) % PAGE_SIZE;
         if remainder != 0 {
-            stackaddr = ((stackaddr as usize) + psize - remainder)
+            stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder)
                 as *mut libc::c_void;
         }
 
@@ -280,60 +312,42 @@ pub unsafe fn init() -> Option<usize> {
             // Instead, we'll just note where we expect rlimit to start
             // faulting, so our handler can report "stack overflow", and
             // trust that the kernel's own stack guard will work.
-            Some(stackaddr as usize)
+            let stackaddr = stackaddr as usize;
+            Some(stackaddr - PAGE_SIZE..stackaddr)
         } else {
             // Reallocate the last page of the stack.
             // This ensures SIGBUS will be raised on
             // stack overflow.
-            let result = mmap(stackaddr, psize, PROT_NONE,
+            let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE,
                               MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
 
             if result != stackaddr || result == MAP_FAILED {
                 panic!("failed to allocate a guard page");
             }
 
+            let guardaddr = stackaddr as usize;
             let offset = if cfg!(target_os = "freebsd") {
                 2
             } else {
                 1
             };
 
-            Some(stackaddr as usize + offset * psize)
+            Some(guardaddr..guardaddr + offset * PAGE_SIZE)
         }
     }
 
-    #[cfg(target_os = "solaris")]
-    pub unsafe fn current() -> Option<usize> {
-        let mut current_stack: libc::stack_t = ::mem::zeroed();
-        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
-        Some(current_stack.ss_sp as usize)
-    }
-
-    #[cfg(target_os = "macos")]
-    pub unsafe fn current() -> Option<usize> {
-        Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
-             libc::pthread_get_stacksize_np(libc::pthread_self()))
-    }
-
-    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
-    pub unsafe fn current() -> Option<usize> {
-        let mut current_stack: libc::stack_t = ::mem::zeroed();
-        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
-                                             &mut current_stack), 0);
-
-        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
-        Some(if libc::pthread_main_np() == 1 {
-            // main thread
-            current_stack.ss_sp as usize - current_stack.ss_size + extra
-        } else {
-            // new thread
-            current_stack.ss_sp as usize - current_stack.ss_size
-        })
+    #[cfg(any(target_os = "macos",
+              target_os = "bitrig",
+              target_os = "openbsd",
+              target_os = "solaris"))]
+    pub unsafe fn current() -> Option<Guard> {
+        let stackaddr = get_stack_start()? as usize;
+        Some(stackaddr - PAGE_SIZE..stackaddr)
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
               target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
-    pub unsafe fn current() -> Option<usize> {
+    pub unsafe fn current() -> Option<Guard> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = ::mem::zeroed();
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -352,12 +366,23 @@ pub unsafe fn current() -> Option<usize> {
             assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                    &mut size), 0);
 
+            let stackaddr = stackaddr as usize;
             ret = if cfg!(target_os = "freebsd") {
-                Some(stackaddr as usize - guardsize)
+                // FIXME does freebsd really fault *below* the guard addr?
+                let guardaddr = stackaddr - guardsize;
+                Some(guardaddr - PAGE_SIZE..guardaddr)
             } else if cfg!(target_os = "netbsd") {
-                Some(stackaddr as usize)
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
+                // glibc used to include the guard area within the stack, as noted in the BUGS
+                // section of `man pthread_attr_getguardsize`.  This has been corrected starting
+                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+                // end (below) the stack.  There's no easy way for us to know which we have at
+                // runtime, so we'll just match any fault in the range right above or below the
+                // stack base to call that fault a stack overflow.
+                Some(stackaddr - guardsize..stackaddr + guardsize)
             } else {
-                Some(stackaddr as usize + guardsize)
+                Some(stackaddr..stackaddr + guardsize)
             };
         }
         assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
index d2a4a7b19d548427711a0068c8ae1214dacf73a3..b3c6b671e809949c9bca2b0d43bdc68999f42a5e 100644 (file)
@@ -10,8 +10,8 @@
 
 use ffi::OsString;
 use marker::PhantomData;
-use mem;
 use vec;
+use sys::ArgsSysCall;
 
 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
     // On wasm these should always be null, so there's nothing for us to do here
@@ -21,38 +21,10 @@ pub unsafe fn cleanup() {
 }
 
 pub fn args() -> Args {
-    // When the runtime debugging is enabled we'll link to some extra runtime
-    // functions to actually implement this. These are for now just implemented
-    // in a node.js script but they're off by default as they're sort of weird
-    // in a web-wasm world.
-    if !super::DEBUG {
-        return Args {
-            iter: Vec::new().into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
-    }
-
-    // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
-    // are just meant for debugging and should not be relied on.
-    extern {
-        fn rust_wasm_args_count() -> usize;
-        fn rust_wasm_args_arg_size(a: usize) -> usize;
-        fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
-    }
-
-    unsafe {
-        let cnt = rust_wasm_args_count();
-        let mut v = Vec::with_capacity(cnt);
-        for i in 0..cnt {
-            let n = rust_wasm_args_arg_size(i);
-            let mut data = vec![0; n];
-            rust_wasm_args_arg_fill(i, data.as_mut_ptr());
-            v.push(mem::transmute::<Vec<u8>, OsString>(data));
-        }
-        Args {
-            iter: v.into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
+    let v = ArgsSysCall::perform();
+    Args {
+        iter: v.into_iter(),
+        _dont_send_or_sync_me: PhantomData,
     }
 }
 
index ba3d6a2813a451a28573303ccbd08cfe625584db..c02e5e809c8bb33cb81553eec35607420553fbd4 100644 (file)
 
 use io;
 use os::raw::c_char;
-
-// Right now the wasm backend doesn't even have the ability to print to the
-// console by default. Wasm can't import anything from JS! (you have to
-// explicitly provide it).
-//
-// Sometimes that's a real bummer, though, so this flag can be set to `true` to
-// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
-// help receive debug output and see what's going on. In general this flag
-// currently controls "will we call out to our own defined shims in node.js",
-// and this flag should always be `false` for release builds.
-const DEBUG: bool = false;
+use ptr;
+use sys::os_str::Buf;
+use sys_common::{AsInner, FromInner};
+use ffi::{OsString, OsStr};
+use time::Duration;
 
 pub mod args;
 #[cfg(feature = "backtrace")]
@@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    ::intrinsics::abort();
+    ExitSysCall::perform(1)
 }
 
 // We don't have randomness yet, but I totally used a random number generator to
@@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! {
 pub fn hashmap_random_keys() -> (u64, u64) {
     (1, 2)
 }
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+    Read = 0,
+    Write = 1,
+    Exit = 2,
+    Args = 3,
+    GetEnv = 4,
+    SetEnv = 5,
+    Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+    fd: usize,
+    ptr: *mut u8,
+    len: usize,
+    result: usize,
+}
+
+impl ReadSysCall {
+    pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+        let mut call_record = ReadSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_mut_ptr(),
+            result: 0
+        };
+        if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+            call_record.result
+        } else {
+            0
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+    fd: usize,
+    ptr: *const u8,
+    len: usize,
+}
+
+impl WriteSysCall {
+    pub fn perform(fd: usize, buffer: &[u8]) {
+        let mut call_record = WriteSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_ptr()
+        };
+        unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+    }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+    code: usize,
+}
+
+impl ExitSysCall {
+    pub fn perform(code: usize) -> ! {
+        let mut call_record = ExitSysCall {
+            code
+        };
+        unsafe {
+            syscall(SysCallIndex::Exit, &mut call_record);
+            ::intrinsics::abort();
+        }
+    }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+    -> Result<Vec<u8>, E>
+{
+    let mut buffer = vec![0; estimate];
+    loop {
+        let result = f(&mut buffer)?;
+        if result <= buffer.len() {
+            buffer.truncate(result);
+            break;
+        }
+        buffer.resize(result, 0);
+    }
+    Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+    ptr: *mut u8,
+    len: usize,
+    result: usize
+}
+
+impl ArgsSysCall {
+    pub fn perform() -> Vec<OsString> {
+        receive_buffer(1024, |buffer| -> Result<usize, !> {
+            let mut call_record = ArgsSysCall {
+                len: buffer.len(),
+                ptr: buffer.as_mut_ptr(),
+                result: 0
+            };
+            if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+                Ok(call_record.result)
+            } else {
+                Ok(0)
+            }
+        })
+            .unwrap()
+            .split(|b| *b == 0)
+            .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+            .collect()
+    }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *mut u8,
+    value_len: usize,
+    result: usize
+}
+
+impl GetEnvSysCall {
+    pub fn perform(key: &OsStr) -> Option<OsString> {
+        let key_buf = &AsInner::as_inner(key).inner;
+        receive_buffer(64, |buffer| {
+            let mut call_record = GetEnvSysCall {
+                key_len: key_buf.len(),
+                key_ptr: key_buf.as_ptr(),
+                value_len: buffer.len(),
+                value_ptr: buffer.as_mut_ptr(),
+                result: !0usize
+            };
+            if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+                if call_record.result == !0usize {
+                    Err(())
+                } else {
+                    Ok(call_record.result)
+                }
+            } else {
+                Err(())
+            }
+        }).ok().map(|s| {
+            FromInner::from_inner(Buf { inner: s })
+        })
+    }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *const u8,
+    value_len: usize
+}
+
+impl SetEnvSysCall {
+    pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+        let key_buf = &AsInner::as_inner(key).inner;
+        let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+        let mut call_record = SetEnvSysCall {
+            key_len: key_buf.len(),
+            key_ptr: key_buf.as_ptr(),
+            value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+            value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+        };
+        unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+    }
+}
+
+pub enum TimeClock {
+    Monotonic = 0,
+    System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+    clock: usize,
+    secs_hi: usize,
+    secs_lo: usize,
+    nanos: usize
+}
+
+impl TimeSysCall {
+    pub fn perform(clock: TimeClock) -> Duration {
+        let mut call_record = TimeSysCall {
+            clock: clock as usize,
+            secs_hi: 0,
+            secs_lo: 0,
+            nanos: 0
+        };
+        if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+            Duration::new(
+                ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+                call_record.nanos as u32
+            )
+        } else {
+            panic!("Time system call is not implemented by WebAssembly host");
+        }
+    }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+    #[cfg(feature = "wasm_syscall")]
+    extern {
+        #[no_mangle]
+        fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+    }
+
+    #[cfg(not(feature = "wasm_syscall"))]
+    unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+    rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
index c98030f7ebf532f7bd843f981d6ea48dacfbba90..23ca1754719be9905fcdb27e102710ca83277ccd 100644 (file)
@@ -8,16 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::intrinsics;
-
 use error::Error as StdError;
 use ffi::{OsString, OsStr};
 use fmt;
 use io;
-use mem;
 use path::{self, PathBuf};
 use str;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
 
 pub fn errno() -> i32 {
     0
@@ -87,36 +84,15 @@ pub fn env() -> Env {
 }
 
 pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    // If we're debugging the runtime then we actually probe node.js to ask for
-    // the value of environment variables to help provide inputs to programs.
-    // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
-    // intended for debugging only, you should not rely on them.
-    if !super::DEBUG {
-        return Ok(None)
-    }
-
-    extern {
-        fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
-        fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
-    }
-    unsafe {
-        let k: &[u8] = mem::transmute(k);
-        let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
-        if n == -1 {
-            return Ok(None)
-        }
-        let mut data = vec![0; n as usize];
-        rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
-        Ok(Some(mem::transmute(data)))
-    }
+    Ok(GetEnvSysCall::perform(k))
 }
 
-pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, Some(v)))
 }
 
-pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, None))
 }
 
 pub fn temp_dir() -> PathBuf {
@@ -128,7 +104,7 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    unsafe { intrinsics::abort() }
+    ExitSysCall::perform(_code as isize as usize)
 }
 
 pub fn getpid() -> u32 {
index 0f75f240251832e5587aac6334afcf6db590916b..beb19c0ed2c1f62bd17b1611db911eb9a04eb7af 100644 (file)
@@ -9,19 +9,19 @@
 // except according to those terms.
 
 use io;
-use sys::{Void, unsupported};
+use sys::{ReadSysCall, WriteSysCall};
 
-pub struct Stdin(Void);
+pub struct Stdin;
 pub struct Stdout;
 pub struct Stderr;
 
 impl Stdin {
     pub fn new() -> io::Result<Stdin> {
-        unsupported()
+        Ok(Stdin)
     }
 
-    pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
+    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+        Ok(ReadSysCall::perform(0, data))
     }
 }
 
@@ -31,19 +31,7 @@ pub fn new() -> io::Result<Stdout> {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // If runtime debugging is enabled at compile time we'll invoke some
-        // runtime functions that are defined in our src/etc/wasm32-shim.js
-        // debugging script. Note that this ffi function call is intended
-        // *purely* for debugging only and should not be relied upon.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stdout(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stdout(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(1, data);
         Ok(data.len())
     }
 
@@ -58,16 +46,7 @@ pub fn new() -> io::Result<Stderr> {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // See comments in stdout for what's going on here.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stderr(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stderr(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(2, data);
         Ok(data.len())
     }
 
index 13980e0cc19d1bae2fc8a161467283ec01c3c41e..6a066509b492a6c1adac441367f233e1ed7c2726 100644 (file)
@@ -43,6 +43,7 @@ pub fn join(self) {
 }
 
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
 }
index c269def98f6ffdae4f226414e678871adc3e6df7..e52435e63398f226e6cb735a431012f7eb0b3350 100644 (file)
@@ -8,56 +8,50 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use fmt;
 use time::Duration;
+use sys::{TimeSysCall, TimeClock};
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant;
+pub struct Instant(Duration);
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct SystemTime;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
 
-pub const UNIX_EPOCH: SystemTime = SystemTime;
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        panic!("not supported on web assembly");
+        Instant(TimeSysCall::perform(TimeClock::Monotonic))
     }
 
-    pub fn sub_instant(&self, _other: &Instant) -> Duration {
-        panic!("can't sub yet");
+    pub fn sub_instant(&self, other: &Instant) -> Duration {
+        self.0 - other.0
     }
 
-    pub fn add_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't add yet");
+    pub fn add_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 + *other)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't sub yet");
+    pub fn sub_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 - *other)
     }
 }
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        panic!("not supported on web assembly");
+        SystemTime(TimeSysCall::perform(TimeClock::System))
     }
 
-    pub fn sub_time(&self, _other: &SystemTime)
+    pub fn sub_time(&self, other: &SystemTime)
                     -> Result<Duration, Duration> {
-        panic!()
-    }
-
-    pub fn add_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+    pub fn add_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 + *other)
     }
-}
 
-impl fmt::Debug for SystemTime {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
-        panic!()
+    pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 - *other)
     }
 }
index 74786d092855f091d8b51e9d837d2040d72d1a29..43abfbb1f645e9852974df82d7a26f2dc706787d 100644 (file)
@@ -93,6 +93,7 @@ pub fn into_handle(self) -> Handle { self.handle }
 
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
 }
index 7970042b1d67ded6faaccfdebb8e4bc762bfba0e..6a2b6742367a5b4ce6032cfe943b9708fb9b9da9 100644 (file)
 #![allow(dead_code)] // stack_guard isn't used right now on all platforms
 
 use cell::RefCell;
+use sys::thread::guard::Guard;
 use thread::Thread;
 
 struct ThreadInfo {
-    stack_guard: Option<usize>,
+    stack_guard: Option<Guard>,
     thread: Thread,
 }
 
@@ -38,11 +39,11 @@ pub fn current_thread() -> Option<Thread> {
     ThreadInfo::with(|info| info.thread.clone())
 }
 
-pub fn stack_guard() -> Option<usize> {
-    ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
+pub fn stack_guard() -> Option<Guard> {
+    ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
 }
 
-pub fn set(stack_guard: Option<usize>, thread: Thread) {
+pub fn set(stack_guard: Option<Guard>, thread: Thread) {
     THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
     THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
         stack_guard,
index 73810b3fe81d73cc02bc58bca039e36f7ad06536..c7ab6158256bae9fd624d77345123f6f1142b109 100644 (file)
@@ -883,7 +883,6 @@ pub struct Arm {
     pub pats: Vec<P<Pat>>,
     pub guard: Option<P<Expr>>,
     pub body: P<Expr>,
-    pub beginning_vert: Option<Span>, // For RFC 1925 feature gate
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
index a6a7f9e20b3a925fa9a236881fd045d0f37080ec..3601b9ba8a8c1cdbf8b5669f1fd42e5f0b17cf17 100644 (file)
@@ -593,8 +593,30 @@ pub fn span_until_char(&self, sp: Span, c: char) -> Span {
         }
     }
 
-    /// Given a `Span`, try to get a shorter span ending just after the first
-    /// occurrence of `char` `c`.
+    /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
+    /// the original `Span`.
+    ///
+    /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
+    pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
+        if let Ok(snippet) = self.span_to_snippet(sp) {
+            let mut offset = 0;
+            // get the bytes width of all the non-whitespace characters
+            for c in snippet.chars().take_while(|c| !c.is_whitespace()) {
+                offset += c.len_utf8();
+            }
+            // get the bytes width of all the whitespace characters after that
+            for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) {
+                offset += c.len_utf8();
+            }
+            if offset > 1 {
+                return sp.with_hi(BytePos(sp.lo().0 + offset as u32));
+            }
+        }
+        sp
+    }
+
+    /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
+    /// `c`.
     pub fn span_through_char(&self, sp: Span, c: char) -> Span {
         if let Ok(snippet) = self.span_to_snippet(sp) {
             if let Some(offset) = snippet.find(c) {
index cf63592c2ece2191448c20119e747676d1c00aad..2e6de96d65a6dfcd86cce0cfcec93d06037c1d1a 100644 (file)
@@ -883,7 +883,6 @@ fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::A
             pats,
             guard: None,
             body: expr,
-            beginning_vert: None,
         }
     }
 
index 9a2560b04583da01b3c68ddcec65ebe9842e4afc..9c6520cd874a8ec87bdc2a3af0bd44b160adef4e 100644 (file)
@@ -386,9 +386,6 @@ pub fn new() -> Features {
     // allow `#[must_use]` on functions and comparison operators (RFC 1940)
     (active, fn_must_use, "1.21.0", Some(43302)),
 
-    // allow '|' at beginning of match arms (RFC 1925)
-    (active, match_beginning_vert, "1.21.0", Some(44101)),
-
     // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
     (active, non_exhaustive, "1.22.0", Some(44109)),
 
@@ -426,9 +423,6 @@ pub fn new() -> Features {
     // In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
     (active, in_band_lifetimes, "1.23.0", Some(44524)),
 
-    // Nested groups in `use` (RFC 2128)
-    (active, use_nested_groups, "1.23.0", Some(44494)),
-
     // generic associated types (RFC 1598)
     (active, generic_associated_types, "1.23.0", Some(44265)),
 
@@ -545,6 +539,10 @@ pub fn new() -> Features {
     (accepted, abi_sysv64, "1.24.0", Some(36167)),
     // Allows `repr(align(16))` struct attribute (RFC 1358)
     (accepted, repr_align, "1.24.0", Some(33626)),
+    // allow '|' at beginning of match arms (RFC 1925)
+    (accepted, match_beginning_vert, "1.25.0", Some(44101)),
+    // Nested groups in `use` (RFC 2128)
+    (accepted, use_nested_groups, "1.25.0", Some(44494)),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -788,6 +786,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                                        is just used for rustc unit tests \
                                                        and will never be stable",
                                                       cfg_fn!(rustc_attrs))),
+    ("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
+                                             "rustc_attrs",
+                                             "the `#[rustc_serialize_exclude_null]` attribute \
+                                              is an internal-only feature",
+                                             cfg_fn!(rustc_attrs))),
     ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
                                                       "rustc_attrs",
                                                       "this attribute \
@@ -1678,11 +1681,6 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
     }
 
     fn visit_arm(&mut self, arm: &'a ast::Arm) {
-        if let Some(span) = arm.beginning_vert {
-            gate_feature_post!(&self, match_beginning_vert,
-                               span,
-                               "Use of a '|' at the beginning of a match arm is experimental")
-        }
         visit::walk_arm(self, arm)
     }
 
@@ -1806,29 +1804,6 @@ fn visit_path(&mut self, path: &'a ast::Path, _id: NodeId) {
         visit::walk_path(self, path);
     }
 
-    fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, nested: bool) {
-        if nested {
-            match use_tree.kind {
-                ast::UseTreeKind::Simple(_) => {
-                    if use_tree.prefix.segments.len() != 1 {
-                        gate_feature_post!(&self, use_nested_groups, use_tree.span,
-                                           "paths in `use` groups are experimental");
-                    }
-                }
-                ast::UseTreeKind::Glob => {
-                    gate_feature_post!(&self, use_nested_groups, use_tree.span,
-                                       "glob imports in `use` groups are experimental");
-                }
-                ast::UseTreeKind::Nested(_) => {
-                    gate_feature_post!(&self, use_nested_groups, use_tree.span,
-                                       "nested groups in `use` are experimental");
-                }
-            }
-        }
-
-        visit::walk_use_tree(self, use_tree, id);
-    }
-
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
         if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
             gate_feature_post!(&self, crate_visibility_modifier, span,
index 0f8fe57e380e557e02379331bcdb4b774ffce223..921ed3565a47197400fa72c6d560366516cb16bf 100644 (file)
@@ -340,14 +340,13 @@ pub fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> Thi
     fold_attrs(attrs.into(), fld).into()
 }
 
-pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body, beginning_vert}: Arm,
+pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
     fld: &mut T) -> Arm {
     Arm {
         attrs: fold_attrs(attrs, fld),
         pats: pats.move_map(|x| fld.fold_pat(x)),
         guard: guard.map(|x| fld.fold_expr(x)),
         body: fld.fold_expr(body),
-        beginning_vert,
     }
 }
 
index 7635ec26b289b347cec9f39ff140cf49fbcf2bb7..98d5fa8f797fa7e105838655419bfd607feb29b7 100644 (file)
@@ -38,34 +38,41 @@ pub struct JsonEmitter {
     registry: Option<Registry>,
     cm: Rc<CodeMapper + 'static>,
     pretty: bool,
+    /// Whether "approximate suggestions" are enabled in the config
+    approximate_suggestions: bool,
 }
 
 impl JsonEmitter {
     pub fn stderr(registry: Option<Registry>,
                   code_map: Rc<CodeMap>,
-                  pretty: bool) -> JsonEmitter {
+                  pretty: bool,
+                  approximate_suggestions: bool) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::stderr()),
             registry,
             cm: code_map,
             pretty,
+            approximate_suggestions,
         }
     }
 
     pub fn basic(pretty: bool) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
-        JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
+        JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
+                            pretty, false)
     }
 
     pub fn new(dst: Box<Write + Send>,
                registry: Option<Registry>,
                code_map: Rc<CodeMap>,
-               pretty: bool) -> JsonEmitter {
+               pretty: bool,
+               approximate_suggestions: bool) -> JsonEmitter {
         JsonEmitter {
             dst,
             registry,
             cm: code_map,
             pretty,
+            approximate_suggestions,
         }
     }
 }
@@ -101,6 +108,7 @@ struct Diagnostic {
 }
 
 #[derive(RustcEncodable)]
+#[allow(unused_attributes)]
 struct DiagnosticSpan {
     file_name: String,
     byte_start: u32,
@@ -121,6 +129,9 @@ struct DiagnosticSpan {
     /// If we are suggesting a replacement, this will contain text
     /// that should be sliced in atop this span.
     suggested_replacement: Option<String>,
+    /// If the suggestion is approximate
+    #[rustc_serialize_exclude_null]
+    suggestion_approximate: Option<bool>,
     /// Macro invocations that created the code at this span, if any.
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
@@ -220,7 +231,7 @@ fn from_sub_diagnostic(db: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
 
 impl DiagnosticSpan {
     fn from_span_label(span: SpanLabel,
-                       suggestion: Option<&String>,
+                       suggestion: Option<(&String, bool)>,
                        je: &JsonEmitter)
                        -> DiagnosticSpan {
         Self::from_span_etc(span.span,
@@ -233,7 +244,7 @@ fn from_span_label(span: SpanLabel,
     fn from_span_etc(span: Span,
                      is_primary: bool,
                      label: Option<String>,
-                     suggestion: Option<&String>,
+                     suggestion: Option<(&String, bool)>,
                      je: &JsonEmitter)
                      -> DiagnosticSpan {
         // obtain the full backtrace from the `macro_backtrace`
@@ -253,7 +264,7 @@ fn from_span_etc(span: Span,
     fn from_span_full(span: Span,
                       is_primary: bool,
                       label: Option<String>,
-                      suggestion: Option<&String>,
+                      suggestion: Option<(&String, bool)>,
                       mut backtrace: vec::IntoIter<MacroBacktrace>,
                       je: &JsonEmitter)
                       -> DiagnosticSpan {
@@ -281,6 +292,13 @@ fn from_span_full(span: Span,
                 def_site_span,
             })
         });
+
+        let suggestion_approximate = if je.approximate_suggestions {
+             suggestion.map(|x| x.1)
+        } else {
+            None
+        };
+
         DiagnosticSpan {
             file_name: start.file.name.to_string(),
             byte_start: span.lo().0 - start.file.start_pos.0,
@@ -291,7 +309,8 @@ fn from_span_full(span: Span,
             column_end: end.col.0 + 1,
             is_primary,
             text: DiagnosticSpanLine::from_span(span, je),
-            suggested_replacement: suggestion.cloned(),
+            suggested_replacement: suggestion.map(|x| x.0.clone()),
+            suggestion_approximate,
             expansion: backtrace_step,
             label,
         }
@@ -309,14 +328,15 @@ fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
         suggestion.substitutions
                       .iter()
                       .flat_map(|substitution| {
-                          substitution.parts.iter().map(move |suggestion| {
+                          substitution.parts.iter().map(move |suggestion_inner| {
                               let span_label = SpanLabel {
-                                  span: suggestion.span,
+                                  span: suggestion_inner.span,
                                   is_primary: true,
                                   label: None,
                               };
                               DiagnosticSpan::from_span_label(span_label,
-                                                              Some(&suggestion.snippet),
+                                                              Some((&suggestion_inner.snippet,
+                                                                   suggestion.approximate)),
                                                               je)
                           })
                       })
index 3b4c5da10f20b35b5f0014a956419e00b4125d11..9181cca215c848602d3f8bbe1a93a3ac45561588 100644 (file)
@@ -25,6 +25,7 @@
 #![feature(match_default_bindings)]
 #![feature(i128_type)]
 #![feature(const_atomic_usize_new)]
+#![feature(rustc_attrs)]
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
 #[allow(unused_extern_crates)]
index 0fd069b76aadc6db18963786525c78f71ab94f06..11ab84a572916e76edc6f7473f6e4cb17cf74787 100644 (file)
@@ -246,14 +246,27 @@ fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
         self.err_span(self.mk_sp(from_pos, to_pos), m)
     }
 
+    /// Pushes a character to a message string for error reporting
+    fn push_escaped_char_for_msg(m: &mut String, c: char) {
+        match c {
+            '\u{20}'...'\u{7e}' => {
+                // Don't escape \, ' or " for user-facing messages
+                m.push(c);
+            }
+            _ => {
+                for c in c.escape_default() {
+                    m.push(c);
+                }
+            }
+        }
+    }
+
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
     /// escaped character to the error message
     fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() {
-            m.push(c)
-        }
+        Self::push_escaped_char_for_msg(&mut m, c);
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
     fn struct_fatal_span_char(&self,
@@ -264,9 +277,7 @@ fn struct_fatal_span_char(&self,
                               -> DiagnosticBuilder<'a> {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() {
-            m.push(c)
-        }
+        Self::push_escaped_char_for_msg(&mut m, c);
         self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
@@ -275,9 +286,7 @@ fn struct_fatal_span_char(&self,
     fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() {
-            m.push(c)
-        }
+        Self::push_escaped_char_for_msg(&mut m, c);
         self.err_span_(from_pos, to_pos, &m[..]);
     }
     fn struct_err_span_char(&self,
@@ -288,9 +297,7 @@ fn struct_err_span_char(&self,
                             -> DiagnosticBuilder<'a> {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() {
-            m.push(c)
-        }
+        Self::push_escaped_char_for_msg(&mut m, c);
         self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
index b3c485a85c0632ecce7ba883acc2a6fc2ced86a7..dc3745fc4a3eebb9d3f461f3e7bdf3f6dd63575f 100644 (file)
@@ -761,6 +761,18 @@ fn interpolated_or_expr_span(&self,
         })
     }
 
+    fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
+        let mut err = self.struct_span_err(self.span,
+                                           &format!("expected identifier, found {}",
+                                                    self.this_token_descr()));
+        if let Some(token_descr) = self.token_descr() {
+            err.span_label(self.span, format!("expected identifier, found {}", token_descr));
+        } else {
+            err.span_label(self.span, "expected identifier");
+        }
+        err
+    }
+
     pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
         self.parse_ident_common(true)
     }
@@ -769,15 +781,7 @@ fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
         match self.token {
             token::Ident(i) => {
                 if self.token.is_reserved_ident() {
-                    let mut err = self.struct_span_err(self.span,
-                                                       &format!("expected identifier, found {}",
-                                                                self.this_token_descr()));
-                    if let Some(token_descr) = self.token_descr() {
-                        err.span_label(self.span, format!("expected identifier, found {}",
-                                                          token_descr));
-                    } else {
-                        err.span_label(self.span, "expected identifier");
-                    }
+                    let mut err = self.expected_ident_found();
                     if recover {
                         err.emit();
                     } else {
@@ -791,14 +795,7 @@ fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
                 Err(if self.prev_token_kind == PrevTokenKind::DocComment {
                         self.span_fatal_err(self.prev_span, Error::UselessDocComment)
                     } else {
-                        let mut err = self.fatal(&format!("expected identifier, found `{}`",
-                                                          self.this_token_to_string()));
-                        if let Some(token_descr) = self.token_descr() {
-                            err.span_label(self.span, format!("expected identifier, found {}",
-                                                              token_descr));
-                        } else {
-                            err.span_label(self.span, "expected identifier");
-                        }
+                        let mut err = self.expected_ident_found();
                         if self.token == token::Underscore {
                             err.note("`_` is a wildcard pattern, not an identifier");
                         }
@@ -3398,11 +3395,7 @@ pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
 
         let attrs = self.parse_outer_attributes()?;
         // Allow a '|' before the pats (RFC 1925)
-        let beginning_vert = if self.eat(&token::BinOp(token::Or)) {
-            Some(self.prev_span)
-        } else {
-            None
-        };
+        self.eat(&token::BinOp(token::Or));
         let pats = self.parse_pats()?;
         let guard = if self.eat_keyword(keywords::If) {
             Some(self.parse_expr()?)
@@ -3426,7 +3419,6 @@ pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
             pats,
             guard,
             body: expr,
-            beginning_vert,
         })
     }
 
index 2be93c07d5ad771774fd5beaa727d9a284db04d1..7fbe781e9a1f6c74b0071394677b3b5d6df3f09c 100644 (file)
@@ -112,6 +112,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool {
         keywords::Unsafe.name(),
         keywords::While.name(),
         keywords::Yield.name(),
+        keywords::Static.name(),
     ].contains(&ident.name)
 }
 
index 3742fb8c804d71993498fd7df05bd54d41be3b26..d1de4dccd00430b4d3885c3635d7d556b1c1eb00 100644 (file)
@@ -239,6 +239,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
         }
     }
 
+    // If there are no outputs, the inline assembly is executed just for its side effects,
+    // so ensure that it is volatile
+    if outputs.is_empty() {
+        volatile = true;
+    }
+
     MacEager::expr(P(ast::Expr {
         id: ast::DUMMY_NODE_ID,
         node: ast::ExprKind::InlineAsm(P(ast::InlineAsm {
index 0e6e96438d8176ffc16065ee9fc21d3d5c41ae1c..743f22b6b314075a34d3a76c9cc44de77fb6abab 100644 (file)
@@ -190,7 +190,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
         Struct(_, ref fields) => {
             let emit_struct_field = cx.ident_of("emit_struct_field");
             let mut stmts = Vec::new();
-            for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
+            for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
                 let name = match name {
                     Some(id) => id.name,
                     None => Symbol::intern(&format!("_field{}", i)),
@@ -212,7 +212,19 @@ fn encodable_substructure(cx: &mut ExtCtxt,
                 } else {
                     cx.expr(span, ExprKind::Ret(Some(call)))
                 };
-                stmts.push(cx.stmt_expr(call));
+
+                // This exists for https://github.com/rust-lang/rust/pull/47540
+                //
+                // If we decide to stabilize that flag this can be removed
+                let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
+                    let is_some = cx.ident_of("is_some");
+                    let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
+                    cx.expr_if(span, condition, call, None)
+                } else {
+                    call
+                };
+                let stmt = cx.stmt_expr(expr);
+                stmts.push(stmt);
             }
 
             // unit structs have no fields and need to return Ok()
index dd1ec7284f6901320987f68a3bd325bf2ad5201f..294506625bc05bc1c07f9ae6f3b3816630821b66 100644 (file)
@@ -347,13 +347,24 @@ pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
 
     /// Return a `Span` that would enclose both `self` and `end`.
     pub fn to(self, end: Span) -> Span {
-        let span = self.data();
-        let end = end.data();
+        let span_data = self.data();
+        let end_data = end.data();
+        // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+        // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
+        // have an incomplete span than a completely nonsensical one.
+        if span_data.ctxt != end_data.ctxt {
+            if span_data.ctxt == SyntaxContext::empty() {
+                return end;
+            } else if end_data.ctxt == SyntaxContext::empty() {
+                return self;
+            }
+            // both span fall within a macro
+            // FIXME(estebank) check if it is the *same* macro
+        }
         Span::new(
-            cmp::min(span.lo, end.lo),
-            cmp::max(span.hi, end.hi),
-            // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
-            if span.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
+            cmp::min(span_data.lo, end_data.lo),
+            cmp::max(span_data.hi, end_data.hi),
+            if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt },
         )
     }
 
index ffa27688cf1a70d4ac71face0478209e5736bb82..9ea5f39b71feecca2ae04b27164c8c1bc2cbb6b3 100644 (file)
@@ -72,6 +72,7 @@
 use std::thread;
 use std::time::{Instant, Duration};
 use std::borrow::Cow;
+use std::process;
 
 const TEST_WARN_TIMEOUT_S: u64 = 60;
 const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
@@ -266,19 +267,27 @@ pub fn display_output(mut self, display_output: bool) -> Options {
 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
     let mut opts = match parse_opts(args) {
         Some(Ok(o)) => o,
-        Some(Err(msg)) => panic!("{:?}", msg),
+        Some(Err(msg)) => {
+            eprintln!("error: {}", msg);
+            process::exit(101);
+        },
         None => return,
     };
+
     opts.options = options;
     if opts.list {
         if let Err(e) = list_tests_console(&opts, tests) {
-            panic!("io error when listing tests: {:?}", e);
+            eprintln!("error: io error when listing tests: {:?}", e);
+            process::exit(101);
         }
     } else {
         match run_tests_console(&opts, tests) {
             Ok(true) => {}
-            Ok(false) => std::process::exit(101),
-            Err(e) => panic!("io error when running tests: {:?}", e),
+            Ok(false) => process::exit(101),
+            Err(e) => {
+                eprintln!("error: io error when listing tests: {:?}", e);
+                process::exit(101);
+            },
         }
     }
 }
diff --git a/src/test/codegen/no-output-asm-is-volatile.rs b/src/test/codegen/no-output-asm-is-volatile.rs
new file mode 100644 (file)
index 0000000..457d706
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -O
+
+// ignore-asmjs
+
+#![feature(asm)]
+#![crate_type = "lib"]
+
+// Check that inline assembly expressions without any outputs
+// are marked as having side effects / being volatile
+
+// CHECK-LABEL: @assembly
+#[no_mangle]
+pub fn assembly() {
+    unsafe { asm!("") }
+// CHECK: tail call void asm sideeffect "", {{.*}}
+}
index 5b26dade9aff06f4f0c264ebab519ac63063186b..4a489f1edb3b8cbf5f509f29ef7fc0f0409b705b 100644 (file)
@@ -15,7 +15,7 @@
 // ignore-wasm
 // ignore-emscripten
 // ignore-windows
-// no-system-llvm
+// min-system-llvm-version 5.0
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 06dd903b23db83925187cd1b49838c15f8468884..4f4d7ce0dba839126787a7c1f798a5a6d8c51bff 100644 (file)
 
 trait Trait {
     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
+    //~^ NOTE lifetimes in impl do not match this method in trait
 }
 
 struct Foo;
 
 impl Trait for Foo {
     fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
-                                            //~^ lifetimes do not match trait
+    //~^ NOTE lifetimes do not match method in trait
     }
 }
 
index 8e5ba489c565ef5239a113f39a070d11cf32ab7c..fe052f2f47ffda103b01b199ac3f6a1b3e044bac 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(use_nested_groups)]
 #![allow(unused_imports)]
 
 mod foo {}
index 02072e9a1a1f6ab5e298a281e6aa16564dc84786..6028df1883967e30086b35c55b5cc6bd951c70e6 100644 (file)
@@ -22,7 +22,7 @@
     : [u32; (i8::MAX as i8 + 1u8) as usize]
     //~^ ERROR mismatched types
     //~| expected i8, found u8
-    //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
+    //~| ERROR cannot add `u8` to `i8`
     = [0; (i8::MAX as usize) + 1];
 
 
diff --git a/src/test/compile-fail/const-typeid-of.rs b/src/test/compile-fail/const-typeid-of.rs
new file mode 100644 (file)
index 0000000..401125c
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2018 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::any::TypeId;
+
+struct A;
+
+fn main() {
+    const A_ID: TypeId = TypeId::of::<A>();
+    //~^ ERROR `std::any::TypeId::of` is not yet stable as a const fn
+}
index 5012556dedddc3c98c3fc1e0a912243f97568a89..cda83fe54b09ab527acdca32c31a484d28327565 100644 (file)
@@ -10,6 +10,7 @@
 
 trait NoLifetime {
     fn get<'p, T : Test<'p>>(&self) -> T;
+    //~^ NOTE lifetimes in impl do not match this method in trait
 }
 
 trait Test<'p> {
@@ -28,8 +29,8 @@ fn new(buf: &'a mut [u8]) -> Foo<'a> {
 
 impl<'a> NoLifetime for Foo<'a> {
     fn get<'p, T : Test<'a>>(&self) -> T {
-//~^ ERROR E0195
-//~| lifetimes do not match trait
+    //~^ ERROR E0195
+    //~| NOTE lifetimes do not match method in trait
         return *self as T;
     }
 }
diff --git a/src/test/compile-fail/issue-42344.rs b/src/test/compile-fail/issue-42344.rs
new file mode 100644 (file)
index 0000000..2f11ff4
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 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.
+
+static TAB: [&mut [u8]; 0] = [];
+
+pub unsafe fn test() {
+    TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389]
+}
+
+pub fn main() {}
diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs
new file mode 100644 (file)
index 0000000..3b7089f
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2018 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)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+struct Foo {
+    bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+    //~^ ERROR unsupported cyclic reference between types/traits detected
+    x: usize,
+}
+
+fn main() {}
index 06aa4c343fea377e55b222b520e40efca62d2521..dc14eca1e673438122fc447a2cb48c00c46388e6 100644 (file)
@@ -17,5 +17,6 @@ fn write<T: AsRef<[u8]>>(buffer: T) { }
 
 fn main() {
     write(&buf);
-    buf[0]=2;                                   //[mir]~ ERROR E0594
+    buf[0]=2;                                   //[ast]~ ERROR E0389
+                                                //[mir]~^ ERROR E0594
 }
diff --git a/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs b/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs
new file mode 100644 (file)
index 0000000..2a4295f
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#![feature(nll)]
+
+#[derive(Clone)] struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+    let s = 2;
+    let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
+    drop(a);
+    drop(a);
+}
index 1c1fc4799c3d1e8b545e3aba0758cd67437d705d..efa6cc273b6f4a66e32623fbcef67d1f92b73f5c 100644 (file)
@@ -19,8 +19,7 @@ fn foo() {
     let mut x = 22;
     let wrapper = Wrap { w: &mut x };
     x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506]
-    //[mir]~^ ERROR cannot assign to `x` because it is borrowed [E0506]
-    //[mir]~^^ ERROR cannot use `x` because it was mutably borrowed [E0503]
+    //[mir]~^ ERROR cannot use `x` because it was mutably borrowed [E0503]
     *wrapper.w += 1;
 }
 
diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
deleted file mode 100644 (file)
index 617de2c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that explicit region bounds are allowed on the various
-// nominal types (but not on other types) and that they are type
-// checked.
-
-struct Inv<'a> { // invariant w/r/t 'a
-    x: &'a mut &'a isize
-}
-
-pub trait Foo<'a, 't> {
-    fn no_bound<'b>(self, b: Inv<'b>);
-    fn has_bound<'b:'a>(self, b: Inv<'b>);
-    fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
-    fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
-    fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
-}
-
-impl<'a, 't> Foo<'a, 't> for &'a isize {
-    fn no_bound<'b:'a>(self, b: Inv<'b>) {
-        //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
-    }
-
-    fn has_bound<'b>(self, b: Inv<'b>) {
-        //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
-    }
-
-    fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
-        //~^ ERROR method not compatible with trait
-        //
-        // Note: This is a terrible error message. It is caused
-        // because, in the trait, 'b is early bound, and in the impl,
-        // 'c is early bound, so -- after substitution -- the
-        // lifetimes themselves look isomorphic.  We fail because the
-        // lifetimes that appear in the types are in the wrong
-        // order. This should really be fixed by keeping more
-        // information about the lifetime declarations in the trait so
-        // that we can compare better to the impl, even in cross-crate
-        // cases.
-    }
-
-    fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
-    }
-
-    fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
-        //~^ ERROR E0276
-    }
-}
-
-fn main() { }
index 94a98b1582af102c9851de6b226a739bf6db8890..caf510071bd68d11eb1862772d5032127f851e57 100644 (file)
@@ -12,7 +12,7 @@
 
 fn main() {
     <i32 as Add<u32>>::add(1, 2);
-    //~^ ERROR `i32: std::ops::Add<u32>` is not satisfied
+    //~^ ERROR cannot add `u32` to `i32`
     <i32 as Add<i32>>::add(1u32, 2);
     //~^ ERROR mismatched types
     <i32 as Add<i32>>::add(1, 2u32);
index c9408c1f2f88b5de1392912e0341ec1b81b10cd0..d8d83fb5b453707c69d2c8b46de919495d893358 100644 (file)
@@ -52,12 +52,15 @@ fn main() {
 //         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
 //         StorageLive(_3);
 //         StorageLive(_4);
+//         StorageLive(_5);
 //         Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]);
-//         _4 = &ReErased mut (*_2);
-//         Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(9)))]);
-//         _3 = move _4 as *mut i32 (Misc);
+//         _5 = &ReErased mut (*_2);
+//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(9)))]);
+//         _4 = move _5 as *mut i32 (Misc);
+//         _3 = move _4;
 //         EndRegion(ReScope(Node(ItemLocalId(9))));
 //         StorageDead(_4);
+//         StorageDead(_5);
 //         Validate(Release, [_0: bool, _3: *mut i32]);
 //         _0 = const write_42(move _3) -> bb1;
 //     }
index 96311d6de176c64a824e9364e06db938c7c75a74..821015ece77124acff5bd042fc7e4d21960964a4 100644 (file)
@@ -15,7 +15,7 @@
 fn main() {
     // these literals are just silly.
     ''';
-    //~^ ERROR: character constant must be escaped: \'
+    //~^ ERROR: character constant must be escaped: '
 
     // note that this is a literal "\n" byte
     '
diff --git a/src/test/parse-fail/lex-stray-backslash.rs b/src/test/parse-fail/lex-stray-backslash.rs
new file mode 100644 (file)
index 0000000..b6042bb
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+// compile-flags: -Z parse-only
+
+\ //~ ERROR: unknown start of token: \
diff --git a/src/test/run-make/output-filename-conflicts-with-directory/Makefile b/src/test/run-make/output-filename-conflicts-with-directory/Makefile
new file mode 100644 (file)
index 0000000..74e5dcf
--- /dev/null
@@ -0,0 +1,7 @@
+-include ../tools.mk
+
+all:
+       cp foo.rs $(TMPDIR)/foo.rs
+       mkdir $(TMPDIR)/foo
+       $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo 2>&1 \
+               | $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\""
diff --git a/src/test/run-make/output-filename-conflicts-with-directory/foo.rs b/src/test/run-make/output-filename-conflicts-with-directory/foo.rs
new file mode 100644 (file)
index 0000000..3f07b46
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2018 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() {}
index 0554627d67753cd7a79b57140cf66cf41550f1d2..6377038b7be745228d3c2173a3ae6ccf263637a1 100644 (file)
@@ -2,8 +2,11 @@
 
 all:
        cp foo.rs $(TMPDIR)/foo
-       $(RUSTC) $(TMPDIR)/foo 2>&1 \
+       $(RUSTC) $(TMPDIR)/foo -o $(TMPDIR)/foo 2>&1 \
                | $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable"
+       cp bar.rs $(TMPDIR)/bar.rlib
+       $(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \
+               | $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable"
        $(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls $(TMPDIR)/foo 2>&1
        cp foo.rs $(TMPDIR)/foo.rs
        $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \
diff --git a/src/test/run-make/output-filename-overwrites-input/bar.rs b/src/test/run-make/output-filename-overwrites-input/bar.rs
new file mode 100644 (file)
index 0000000..8e4e35f
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
index 046d27a9f0fe55586ed5f82a1533900e04e6b1ec..3f07b46791d22753d7a5492210b1d50c99c07cc7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
index 8a1b57939894685261d0149ed4571b92a912a40c..07322d8bbc3253cb9c03556e479bb50c898c52f1 100644 (file)
@@ -451,3 +451,11 @@ fn test_format_args() {
     static EXTERN_FOO: u8;
     fn extern_foo(a: u8, b: i32) -> String;
 }
+
+struct Rls699 {
+  f: u32,
+}
+
+fn new(f: u32) -> Rls699 {
+    Rls699 { fs }
+}
diff --git a/src/test/run-make/save-analysis/extra-docs.md b/src/test/run-make/save-analysis/extra-docs.md
new file mode 100644 (file)
index 0000000..0605ca5
--- /dev/null
@@ -0,0 +1 @@
+Extra docs for this struct.
index 834a7554a555d4a48a37327f686bc6f3f76e2672..5b4e4802957af8e037c62f96500fe008e1818a55 100644 (file)
@@ -12,6 +12,7 @@
 #![feature(box_syntax)]
 #![feature(rustc_private)]
 #![feature(associated_type_defaults)]
+#![feature(external_doc)]
 
 extern crate graphviz;
 // A simple rust project
@@ -461,3 +462,6 @@ fn next(&mut self) -> Option<Self::Item> {
 trait Foo {
     type Bar = FrameBuffer;
 }
+
+#[doc(include="extra-docs.md")]
+struct StructWithDocs;
diff --git a/src/test/run-pass/const-typeid-of.rs b/src/test/run-pass/const-typeid-of.rs
new file mode 100644 (file)
index 0000000..ce29e55
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 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(core_intrinsics)]
+#![feature(const_type_id)]
+
+use std::any::TypeId;
+
+struct A;
+
+static ID_ISIZE: TypeId = TypeId::of::<isize>();
+
+pub fn main() {
+    assert_eq!(ID_ISIZE, TypeId::of::<isize>());
+
+    // sanity test of TypeId
+    const T: (TypeId, TypeId, TypeId) = (TypeId::of::<usize>(),
+                     TypeId::of::<&'static str>(),
+                     TypeId::of::<A>());
+    let (d, e, f) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),
+                     TypeId::of::<A>());
+
+    assert!(T.0 != T.1);
+    assert!(T.0 != T.2);
+    assert!(T.1 != T.2);
+
+    assert_eq!(T.0, d);
+    assert_eq!(T.1, e);
+    assert_eq!(T.2, f);
+
+    // Check fn pointer against collisions
+    const F: (TypeId, TypeId) = (TypeId::of::<fn(fn(A) -> A) -> A>(),
+            TypeId::of::<fn(fn() -> A, A) -> A>());
+
+    assert!(F.0 != F.1);
+}
diff --git a/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs b/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs
new file mode 100644 (file)
index 0000000..2314533
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2018 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(generators)]
+
+fn main() {
+    unsafe {
+        static move || {
+            // Tests that the generator transformation finds out that `a` is not live
+            // during the yield expression. Type checking will also compute liveness
+            // and it should also find out that `a` is not live.
+            // The compiler will panic if the generator transformation finds that
+            // `a` is live and type checking finds it dead.
+            let a = {
+                yield ();
+                4i32
+            };
+            &a;
+        };
+    }
+}
diff --git a/src/test/run-pass/issue-47139-1.rs b/src/test/run-pass/issue-47139-1.rs
new file mode 100644 (file)
index 0000000..cb87991
--- /dev/null
@@ -0,0 +1,87 @@
+// 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.
+
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+    type Values;
+
+    fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+    where
+    T: Insertable,
+    T::Values: Default,
+{
+    type Values = T::Values;
+
+    fn values(self) -> Self::Values {
+        self.map(Insertable::values).unwrap_or_default()
+    }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+    where
+    Option<&'a T>: Insertable,
+{
+    type Values = <Option<&'a T> as Insertable>::Values;
+
+    fn values(self) -> Self::Values {
+        self.as_ref().values()
+    }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+    type Values = Self;
+
+    fn values(self) -> Self::Values {
+        self
+    }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+    where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+    where T: Unimplemented
+{ }
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-47139-2.rs b/src/test/run-pass/issue-47139-2.rs
new file mode 100644 (file)
index 0000000..08eaee5
--- /dev/null
@@ -0,0 +1,75 @@
+// 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.
+
+// Regression test for issue #47139:
+//
+// Same as issue-47139-1.rs, but the impls of dummy are in the
+// opposite order. This influenced the way that coherence ran and in
+// some cases caused the overflow to occur when it wouldn't otherwise.
+// In an effort to make the regr test more robust, I am including both
+// orderings.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+    type Values;
+
+    fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+    where
+    T: Insertable,
+    T::Values: Default,
+{
+    type Values = T::Values;
+
+    fn values(self) -> Self::Values {
+        self.map(Insertable::values).unwrap_or_default()
+    }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+    where
+    Option<&'a T>: Insertable,
+{
+    type Values = <Option<&'a T> as Insertable>::Values;
+
+    fn values(self) -> Self::Values {
+        self.as_ref().values()
+    }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+    type Values = Self;
+
+    fn values(self) -> Self::Values {
+        self
+    }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<T> Dummy for T
+    where T: Unimplemented
+{ }
+
+impl<'a, U> Dummy for Foo<&'a U>
+    where &'a U: Insertable
+{
+}
+
+fn main() {
+}
index 92f54a44f63c94ae0af9c11fbba66de1f0e2b1ef..22f7f169e298840e9ef7ffb0bdc6e3bd75a9e72d 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(use_nested_groups)]
 #![allow(unused_import)]
 
 use {{}, {}};
diff --git a/src/test/run-pass/issue-47722.rs b/src/test/run-pass/issue-47722.rs
new file mode 100644 (file)
index 0000000..3b5d808
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2018 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.
+//
+// Tests that automatic coercions from &mut T to *mut T
+// allow borrows of T to expire immediately - essentially, that
+// they work identically to 'foo as *mut T'
+#![feature(nll)]
+
+struct SelfReference {
+    self_reference: *mut SelfReference,
+}
+
+impl SelfReference {
+    fn set_self_ref(&mut self) {
+        self.self_reference = self;
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-47789.rs b/src/test/run-pass/issue-47789.rs
new file mode 100644 (file)
index 0000000..3148939
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2018 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(nll)]
+
+static mut x: &'static u32 = &0;
+
+fn foo() {
+    unsafe { x = &1; }
+}
+
+fn main() { }
diff --git a/src/test/run-pass/match-beginning-vert.rs b/src/test/run-pass/match-beginning-vert.rs
new file mode 100644 (file)
index 0000000..cdacfb2
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Foo {
+    A,
+    B,
+    C,
+    D,
+    E,
+}
+use Foo::*;
+
+fn main() {
+    for foo in &[A, B, C, D, E] {
+        match *foo {
+            | A => println!("A"),
+            | B | C if 1 < 2 => println!("BC!"),
+            | _ => {},
+        }
+    }
+}
diff --git a/src/test/run-pass/nll/issue-47589.rs b/src/test/run-pass/nll/issue-47589.rs
new file mode 100644 (file)
index 0000000..393c18e
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2018 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(nll)]
+
+pub struct DescriptorSet<'a> {
+    pub slots: Vec<AttachInfo<'a, Resources>>
+}
+
+pub trait ResourcesTrait<'r>: Sized {
+    type DescriptorSet: 'r;
+}
+
+pub struct Resources;
+
+impl<'a> ResourcesTrait<'a> for Resources {
+    type DescriptorSet = DescriptorSet<'a>;
+}
+
+pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
+    NextDescriptorSet(Box<R::DescriptorSet>)
+}
+
+fn main() {
+    let _x = DescriptorSet {slots: Vec::new()};
+}
index 22555c8d6a779edbf75a49d3822f8dcb870748c1..4deced1297bd11d78332c3f28f7a70b15d9e1c94 100644 (file)
@@ -15,7 +15,7 @@
 // ignore-emscripten no processes
 // ignore-musl FIXME #31506
 // ignore-pretty
-// no-system-llvm
+// min-system-llvm-version 5.0
 // compile-flags: -C lto
 // no-prefer-dynamic
 
index 248ad7019261d1abdfa09e4e0f7c97215e5189a0..4224a65ffd7c71da83ff371af64a6c393338da77 100644 (file)
@@ -14,7 +14,7 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
 // ignore-musl FIXME #31506
-// no-system-llvm
+// min-system-llvm-version 5.0
 
 use std::mem;
 use std::process::Command;
index a28f8da9ff882f31167faa7d0aebbcc4f6e9da60..be06e463e3b37fac7c475e3840c3e9d12bcf481f 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(use_nested_groups)]
-
 mod a {
     pub enum B {}
 
diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs
new file mode 100644 (file)
index 0000000..9fed67e
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+// Just check if we don't get an ICE for the _S type.
+
+#![feature(const_size_of)]
+
+use std::cell::Cell;
+use std::mem;
+
+pub struct S {
+    s: Cell<usize>
+}
+
+pub type _S = [usize; 0 - (mem::size_of::<S>() != 4) as usize];
diff --git a/src/test/rustdoc/issue-47639.rs b/src/test/rustdoc/issue-47639.rs
new file mode 100644 (file)
index 0000000..167c3aa
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2018 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 should not ICE
+pub fn test() {
+    macro_rules! foo {
+        () => ()
+    }
+}
index a7aee9b19f1a1e7c0f80e8c9bb739000fb585554..ab0e1003a9e10d76dad53b835907c202538eef02 100644 (file)
@@ -9,11 +9,8 @@ error[E0308]: mismatched types
 note: the lifetime 'a as defined on the impl at 17:1...
   --> $DIR/associated-const-impl-wrong-lifetime.rs:17:1
    |
-17 | / impl<'a> Foo for &'a () {
-18 | |     const NAME: &'a str = "unit";
-19 | |     //~^ ERROR mismatched types [E0308]
-20 | | }
-   | |_^
+17 | impl<'a> Foo for &'a () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...does not necessarily outlive the static lifetime
 
 error: aborting due to previous error
diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs
new file mode 100644 (file)
index 0000000..617de2c
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+struct Inv<'a> { // invariant w/r/t 'a
+    x: &'a mut &'a isize
+}
+
+pub trait Foo<'a, 't> {
+    fn no_bound<'b>(self, b: Inv<'b>);
+    fn has_bound<'b:'a>(self, b: Inv<'b>);
+    fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+}
+
+impl<'a, 't> Foo<'a, 't> for &'a isize {
+    fn no_bound<'b:'a>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
+    }
+
+    fn has_bound<'b>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
+    }
+
+    fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+        //~^ ERROR method not compatible with trait
+        //
+        // Note: This is a terrible error message. It is caused
+        // because, in the trait, 'b is early bound, and in the impl,
+        // 'c is early bound, so -- after substitution -- the
+        // lifetimes themselves look isomorphic.  We fail because the
+        // lifetimes that appear in the types are in the wrong
+        // order. This should really be fixed by keeping more
+        // information about the lifetime declarations in the trait so
+        // that we can compare better to the impl, even in cross-crate
+        // cases.
+    }
+
+    fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
+    }
+
+    fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+        //~^ ERROR E0276
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
new file mode 100644 (file)
index 0000000..e832324
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
+   |
+20 |     fn no_bound<'b>(self, b: Inv<'b>);
+   |     ---------------------------------- lifetimes in impl do not match this method in trait
+...
+28 |     fn no_bound<'b:'a>(self, b: Inv<'b>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
+   |
+21 |     fn has_bound<'b:'a>(self, b: Inv<'b>);
+   |     -------------------------------------- lifetimes in impl do not match this method in trait
+...
+32 |     fn has_bound<'b>(self, b: Inv<'b>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0308]: method not compatible with trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+   |
+36 |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
+              found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
+note: the lifetime 'c as defined on the method body at 36:5...
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+   |
+36 |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+   |
+36 |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
+   |
+24 |     fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+   |     ------------------------------------------------------- definition of `another_bound` from trait
+...
+53 |     fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`
+
+error: aborting due to 4 previous errors
+
index ebb1e561e57ab6acec3dd4f1e24e891f7b0fd186..5c612522d9a318ae436994942cc92562d383c89a 100644 (file)
@@ -41,14 +41,8 @@ note: the anonymous lifetime #2 defined on the body at 47:29...
 note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
   --> $DIR/expect-region-supply-region.rs:42:1
    |
-42 | / fn expect_bound_supply_named<'x>() {
-43 | |     let mut f: Option<&u32> = None;
-44 | |
-45 | |     // Here we give a type annotation that `x` should be free. We get
-...  |
-54 | |     });
-55 | | }
-   | |_^
+42 | fn expect_bound_supply_named<'x>() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/expect-region-supply-region.rs:47:33
@@ -61,14 +55,8 @@ error[E0308]: mismatched types
 note: the lifetime 'x as defined on the function body at 42:1...
   --> $DIR/expect-region-supply-region.rs:42:1
    |
-42 | / fn expect_bound_supply_named<'x>() {
-43 | |     let mut f: Option<&u32> = None;
-44 | |
-45 | |     // Here we give a type annotation that `x` should be free. We get
-...  |
-54 | |     });
-55 | | }
-   | |_^
+42 | fn expect_bound_supply_named<'x>() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
   --> $DIR/expect-region-supply-region.rs:47:29
    |
diff --git a/src/test/ui/feature-gate-match_beginning_vert.rs b/src/test/ui/feature-gate-match_beginning_vert.rs
deleted file mode 100644 (file)
index 9085563..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[allow(dead_code)]
-enum Foo {
-    A,
-    B,
-    C,
-    D,
-    E,
-}
-use Foo::*;
-
-fn main() {
-    let x = Foo::A;
-    match x {
-        | A => println!("A"),
-        //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-        | B | C => println!("BC!"),
-        //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-        | _ => {},
-        //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-    };
-    match x {
-        A | B | C => println!("ABC!"),
-        _ => {},
-    };
-}
-
diff --git a/src/test/ui/feature-gate-match_beginning_vert.stderr b/src/test/ui/feature-gate-match_beginning_vert.stderr
deleted file mode 100644 (file)
index 1d45ded..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-  --> $DIR/feature-gate-match_beginning_vert.rs:24:9
-   |
-24 |         | A => println!("A"),
-   |         ^
-   |
-   = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-  --> $DIR/feature-gate-match_beginning_vert.rs:26:9
-   |
-26 |         | B | C => println!("BC!"),
-   |         ^
-   |
-   = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
-  --> $DIR/feature-gate-match_beginning_vert.rs:28:9
-   |
-28 |         | _ => {},
-   |         ^
-   |
-   = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/feature-gate-use_nested_groups.rs b/src/test/ui/feature-gate-use_nested_groups.rs
deleted file mode 100644 (file)
index 56413a9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(unused_imports, dead_code)]
-
-mod a {
-    pub enum B {}
-    pub enum C {}
-
-    pub mod d {
-        pub enum E {}
-        pub enum F {}
-
-        pub mod g {
-            pub enum H {}
-        }
-    }
-}
-
-use a::{B, d::{*, g::H}};  //~ ERROR glob imports in `use` groups are experimental
-                           //~^ ERROR nested groups in `use` are experimental
-                           //~^^ ERROR paths in `use` groups are experimental
-
-fn main() {}
diff --git a/src/test/ui/feature-gate-use_nested_groups.stderr b/src/test/ui/feature-gate-use_nested_groups.stderr
deleted file mode 100644 (file)
index 6ae691c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0658]: nested groups in `use` are experimental (see issue #44494)
-  --> $DIR/feature-gate-use_nested_groups.rs:27:12
-   |
-27 | use a::{B, d::{*, g::H}};  //~ ERROR glob imports in `use` groups are experimental
-   |            ^^^^^^^^^^^^
-   |
-   = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error[E0658]: glob imports in `use` groups are experimental (see issue #44494)
-  --> $DIR/feature-gate-use_nested_groups.rs:27:16
-   |
-27 | use a::{B, d::{*, g::H}};  //~ ERROR glob imports in `use` groups are experimental
-   |                ^
-   |
-   = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error[E0658]: paths in `use` groups are experimental (see issue #44494)
-  --> $DIR/feature-gate-use_nested_groups.rs:27:19
-   |
-27 | use a::{B, d::{*, g::H}};  //~ ERROR glob imports in `use` groups are experimental
-   |                   ^^^^
-   |
-   = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
index 0a52a928f69d48bf269625e95b585e95420857d0..0f7d2e540d80a8b6e5f3b5aa063f45f999509e7e 100644 (file)
@@ -1,12 +1,3 @@
-error[E0626]: borrow may still be in use when generator yields (Mir)
-  --> $DIR/generator-with-nll.rs:20:17
-   |
-20 |         let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
-   |                 ^^^^^^^^^
-21 |         //~^ borrow may still be in use when generator yields (Mir)
-22 |         yield ();
-   |         -------- possible yield occurs here
-
 error[E0626]: borrow may still be in use when generator yields (Ast)
   --> $DIR/generator-with-nll.rs:19:23
    |
@@ -25,5 +16,14 @@ error[E0626]: borrow may still be in use when generator yields (Ast)
 22 |         yield ();
    |         -------- possible yield occurs here
 
+error[E0626]: borrow may still be in use when generator yields (Mir)
+  --> $DIR/generator-with-nll.rs:20:17
+   |
+20 |         let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
+   |                 ^^^^^^^^^
+21 |         //~^ borrow may still be in use when generator yields (Mir)
+22 |         yield ();
+   |         -------- possible yield occurs here
+
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generator/pattern-borrow.rs b/src/test/ui/generator/pattern-borrow.rs
new file mode 100644 (file)
index 0000000..557a5e6
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2018 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(generators)]
+
+enum Test { A(i32), B, }
+
+fn main() { }
+
+fn fun(test: Test) {
+    move || {
+        if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+            yield ();
+        }
+    };
+}
diff --git a/src/test/ui/generator/pattern-borrow.stderr b/src/test/ui/generator/pattern-borrow.stderr
new file mode 100644 (file)
index 0000000..6b39b27
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0626]: borrow may still be in use when generator yields
+  --> $DIR/pattern-borrow.rs:19:24
+   |
+19 |         if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+   |                        ^^^^^^
+20 |             yield ();
+   |             -------- possible yield occurs here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs
new file mode 100644 (file)
index 0000000..f38ebf8
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2018 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(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn main() {
+   let s = String::from("foo");
+   let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+       yield s[..];
+   };
+   gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+}
diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr
new file mode 100644 (file)
index 0000000..7adb2cc
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/sized-yield.rs:17:26
+   |
+17 |      let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+   |  __________________________^
+18 | |        yield s[..];
+19 | |    };
+   | |____^ `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = note: the yield type of a generator must have a statically known size
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/sized-yield.rs:20:8
+   |
+20 |    gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+   |        ^^^^^^ `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+
+error: aborting due to 2 previous errors
+
index 7961dd97441369edef268f752aeb66f7dcbfcb01..114fe8ffcab0e02d6d3d0282c84b63d3b690eac1 100644 (file)
@@ -1,12 +1,3 @@
-error[E0626]: borrow may still be in use when generator yields (Mir)
-  --> $DIR/yield-while-local-borrowed.rs:24:17
-   |
-24 |         let a = &mut 3;
-   |                 ^^^^^^
-...
-27 |         yield();
-   |         ------- possible yield occurs here
-
 error[E0626]: borrow may still be in use when generator yields (Ast)
   --> $DIR/yield-while-local-borrowed.rs:24:22
    |
@@ -25,6 +16,15 @@ error[E0626]: borrow may still be in use when generator yields (Ast)
 55 |             yield();
    |             ------- possible yield occurs here
 
+error[E0626]: borrow may still be in use when generator yields (Mir)
+  --> $DIR/yield-while-local-borrowed.rs:24:17
+   |
+24 |         let a = &mut 3;
+   |                 ^^^^^^
+...
+27 |         yield();
+   |         ------- possible yield occurs here
+
 error[E0626]: borrow may still be in use when generator yields (Mir)
   --> $DIR/yield-while-local-borrowed.rs:52:21
    |
index 36df4f0eb4d46f7cc25792807680fa6c622dd3cc..9d9d4cef3119a11c50fb4e59879bf3eb3b94a7c7 100644 (file)
@@ -32,7 +32,7 @@ fn sum_to(n: u32) -> impl Foo {
         0
     } else {
         n + sum_to(n - 1)
-        //~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+        //~^ ERROR cannot add `impl Foo` to `u32`
     }
 }
 
index 3fc08a0900fb9ed7b8213b4d1d78144d3c07cca4..8ec819038031b45bfd7299dd3ada8ed5668754a6 100644 (file)
@@ -7,7 +7,7 @@ error[E0308]: mismatched types
    = note: expected type `i32`
               found type `u32`
 
-error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:34:11
    |
 34 |         n + sum_to(n - 1)
index 7a0d01a8ec2156234c3ed4b82aa90af25830d8a3..1417c71ca1244d3a605722497b42baf3334cacf1 100644 (file)
@@ -2,7 +2,7 @@ error[E0053]: method `fmt` has an incompatible type for trait
   --> $DIR/trait_type.rs:17:4
    |
 17 |    fn fmt(&self, x: &str) -> () { }
-   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
    |
    = note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
               found type `fn(&MyType, &str)`
@@ -19,7 +19,7 @@ error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in th
   --> $DIR/trait_type.rs:27:4
    |
 27 |    fn fmt() -> () { }
-   |    ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+   |    ^^^^^^^^^^^^^^ expected `&self` in impl
    |
    = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
 
diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs b/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs
new file mode 100644 (file)
index 0000000..5151abd
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 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(warnings)]
+#![allow(unused_variables, dead_code, unused, bad_style)]
+#![deny(elided_lifetime_in_path)]
+
+struct Foo<'a> { x: &'a u32 }
+fn foo(x: &Foo) {
+    //~^ ERROR: hidden lifetime parameters are deprecated, try `Foo<'_>`
+}
+
+fn main() {}
diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr
new file mode 100644 (file)
index 0000000..613a7be
--- /dev/null
@@ -0,0 +1,14 @@
+error: hidden lifetime parameters are deprecated, try `Foo<'_>`
+  --> $DIR/ellided-lifetimes.rs:15:12
+   |
+15 | fn foo(x: &Foo) {
+   |            ^^^
+   |
+note: lint level defined here
+  --> $DIR/ellided-lifetimes.rs:12:9
+   |
+12 | #![deny(elided_lifetime_in_path)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs
new file mode 100644 (file)
index 0000000..f845762
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2018 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::ops::Deref;
+trait Trait {}
+
+struct Struct;
+
+impl Deref for Struct {
+    type Target = Trait;
+    fn deref(&self) -> &Trait {
+        unimplemented!();
+    }
+}
+//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
new file mode 100644 (file)
index 0000000..7aab31e
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0601]: main function not found
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
+  --> $DIR/mismatched_trait_impl-2.rs:18:5
+   |
+18 |     fn deref(&self) -> &Trait {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
+  --> $DIR/mismatched_trait_impl-2.rs:18:5
+   |
+18 | /     fn deref(&self) -> &Trait {
+19 | |         unimplemented!();
+20 | |     }
+   | |_____^
+   = note: ...but the lifetime must also be valid for the static lifetime...
+   = note: ...so that the method type is compatible with trait:
+           expected fn(&Struct) -> &Trait + 'static
+              found fn(&Struct) -> &Trait
+
+error: aborting due to 2 previous errors
+
index e96f7181a6daeb80aa2d6774227e74fb786f013d..fd6be01da9f460a44c7066dbcbfd2724ce00980f 100644 (file)
@@ -1,10 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
   --> $DIR/mismatched_trait_impl.rs:19:5
    |
-19 | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | |         x
-21 | |     }
-   | |_____^
+19 |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5...
   --> $DIR/mismatched_trait_impl.rs:19:5
@@ -13,27 +11,14 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
 20 | |         x
 21 | |     }
    | |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
-  --> $DIR/mismatched_trait_impl.rs:19:5
-   |
-19 | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | |         x
-21 | |     }
-   | |_____^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5...
+note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 19:5...
   --> $DIR/mismatched_trait_impl.rs:19:5
    |
-19 | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | |         x
-21 | |     }
-   | |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
-  --> $DIR/mismatched_trait_impl.rs:19:5
-   |
-19 | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | |         x
-21 | |     }
-   | |_____^
+19 |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...so that the method type is compatible with trait:
+           expected fn(&i32, &'a u32, &u32) -> &'a u32
+              found fn(&i32, &u32, &u32) -> &u32
 
 error: aborting due to previous error
 
index b580b8e73137b134e5d43df72fe13e9003a3a70d..b24544743d87da84c5e64e6432854df272775864 100644 (file)
@@ -14,14 +14,8 @@ note: the anonymous lifetime #1 defined on the method body at 15:5...
 note: ...does not necessarily outlive the lifetime 'a as defined on the trait at 13:1
   --> $DIR/issue-27942.rs:13:1
    |
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | |     fn select(&self) -> BufferViewHandle<R>;
-16 | |     //~^ ERROR mismatched types
-...  |
-19 | |     //~| lifetime mismatch
-20 | | }
-   | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-27942.rs:15:5
@@ -34,14 +28,8 @@ error[E0308]: mismatched types
 note: the lifetime 'a as defined on the trait at 13:1...
   --> $DIR/issue-27942.rs:13:1
    |
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | |     fn select(&self) -> BufferViewHandle<R>;
-16 | |     //~^ ERROR mismatched types
-...  |
-19 | |     //~| lifetime mismatch
-20 | | }
-   | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 15:5
   --> $DIR/issue-27942.rs:15:5
    |
index 439b123975f82616802892ed5876344424ad0a84..c4ad232ae7eba6f5b11af4182801ea27da2af831 100644 (file)
@@ -24,14 +24,8 @@ note: the anonymous lifetime #1 defined on the method body at 16:5...
 note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:1
   --> $DIR/issue-37884.rs:13:1
    |
-13 | / impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
-14 | |
-15 | |     type Item = &'a mut T;
-16 | |     fn next(&'a mut self) -> Option<Self::Item>
-...  |
-21 | |     }
-22 | | }
-   | |_^
+13 | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-45697-1.rs b/src/test/ui/issue-45697-1.rs
new file mode 100644 (file)
index 0000000..7734b14
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=on
+
+struct S<'a> {
+    pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+    S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1;
+        //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
+        //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+        *z.pointer += 1;
+    }
+}
diff --git a/src/test/ui/issue-45697-1.stderr b/src/test/ui/issue-45697-1.stderr
new file mode 100644 (file)
index 0000000..09f32b9
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+  --> $DIR/issue-45697-1.rs:30:9
+   |
+29 |         let z = copy_borrowed_ptr(&mut y);
+   |                                        - borrow of `*y.pointer` occurs here
+30 |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+  --> $DIR/issue-45697-1.rs:30:9
+   |
+29 |         let z = copy_borrowed_ptr(&mut y);
+   |                                   ------ borrow of `y` occurs here
+30 |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ use of borrowed `y`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issue-45697.rs b/src/test/ui/issue-45697.rs
new file mode 100644 (file)
index 0000000..4e93ecc
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=off
+
+struct S<'a> {
+    pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+    S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1;
+        //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
+        //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+        *z.pointer += 1;
+    }
+}
diff --git a/src/test/ui/issue-45697.stderr b/src/test/ui/issue-45697.stderr
new file mode 100644 (file)
index 0000000..e9b723d
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+  --> $DIR/issue-45697.rs:30:9
+   |
+29 |         let z = copy_borrowed_ptr(&mut y);
+   |                                        - borrow of `*y.pointer` occurs here
+30 |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+  --> $DIR/issue-45697.rs:30:9
+   |
+29 |         let z = copy_borrowed_ptr(&mut y);
+   |                                   ------ borrow of `y` occurs here
+30 |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ use of borrowed `y`
+
+error: aborting due to 2 previous errors
+
index 2f332a7a55850dc5f74789d067fe88958306f979..7b5cce218e9f26ad8fe4ee1e82a5fb299db62a04 100644 (file)
@@ -10,12 +10,8 @@ error[E0597]: borrowed value does not live long enough (Ast)
 note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
   --> $DIR/issue-46472.rs:13:1
    |
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | |     &mut 4
-15 | |     //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | |     //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
-   | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0597]: borrowed value does not live long enough (Mir)
   --> $DIR/issue-46472.rs:14:10
@@ -29,12 +25,8 @@ error[E0597]: borrowed value does not live long enough (Mir)
 note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
   --> $DIR/issue-46472.rs:13:1
    |
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | |     &mut 4
-15 | |     //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | |     //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
-   | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
new file mode 100644 (file)
index 0000000..b4e6c50
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+
+#![warn(unused_parens)]
+
+macro_rules! the_worship_the_heart_lifts_above {
+    ( @as_expr, $e:expr) => { $e };
+    ( @generate_fn, $name:tt) => {
+        #[allow(dead_code)] fn the_moth_for_the_star<'a>() -> Option<&'a str> {
+            Some(the_worship_the_heart_lifts_above!( @as_expr, $name ))
+        }
+    };
+    ( $name:ident ) => { the_worship_the_heart_lifts_above!( @generate_fn, (stringify!($name))); }
+    // ↑ Notably, this does 𝘯𝘰𝘵 warn: we're declining to lint unused parens in
+    // function/method arguments inside of nested macros because of situations
+    // like those reported in Issue #47775
+}
+
+macro_rules! and_the_heavens_reject_not {
+    () => {
+        // ↓ But let's test that we still lint for unused parens around
+        // function args inside of simple, one-deep macros.
+        #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+        //~^ WARN unnecessary parentheses around function argument
+    }
+}
+
+the_worship_the_heart_lifts_above!(rah);
+and_the_heavens_reject_not!();
+
+fn main() {}
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
new file mode 100644 (file)
index 0000000..097ec1b
--- /dev/null
@@ -0,0 +1,15 @@
+warning: unnecessary parentheses around function argument
+  --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:32:83
+   |
+32 |         #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+   |                                                                                   ^^^ help: remove these parentheses
+...
+38 | and_the_heavens_reject_not!();
+   | ------------------------------ in this macro invocation
+   |
+note: lint level defined here
+  --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:13:9
+   |
+13 | #![warn(unused_parens)]
+   |         ^^^^^^^^^^^^^
+
index dfcaede1402da372ac99f6bc1bcd12964503189c..e35675eacd835cc88f1d7f7e7e25165ec751f7c0 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-tab
+
 #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
 #![feature(no_debug)]
 
@@ -46,11 +48,15 @@ fn main() {
         let mut a = (1); // should suggest no `mut`, no parens
         //~^ WARN does not need to be mutable
         //~| WARN unnecessary parentheses
+        // the line after `mut` has a `\t` at the beginning, this is on purpose
+        let mut
+               b = 1;
+        //~^^ WARN does not need to be mutable
         let d = Equinox { warp_factor: 9.975 };
         match d {
             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
             //~^ WARN this pattern is redundant
         }
-        println!("{}", a);
+        println!("{} {}", a, b);
     }
 }
index 8b30f552d377140a0d49f171ab67e46685819a8b..90d6bd312e419505974bf7d8db881e1f323c87f4 100644 (file)
@@ -1,41 +1,53 @@
 warning: unnecessary parentheses around assigned value
-  --> $DIR/suggestions.rs:46:21
+  --> $DIR/suggestions.rs:48:21
    |
-46 |         let mut a = (1); // should suggest no `mut`, no parens
+48 |         let mut a = (1); // should suggest no `mut`, no parens
    |                     ^^^ help: remove these parentheses
    |
 note: lint level defined here
-  --> $DIR/suggestions.rs:11:21
+  --> $DIR/suggestions.rs:13:21
    |
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
    |                     ^^^^^^^^^^^^^
 
 warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
-  --> $DIR/suggestions.rs:41:1
+  --> $DIR/suggestions.rs:43:1
    |
-41 | #[no_debug] // should suggest removal of deprecated attribute
+43 | #[no_debug] // should suggest removal of deprecated attribute
    | ^^^^^^^^^^^ help: remove this attribute
    |
    = note: #[warn(deprecated)] on by default
 
 warning: variable does not need to be mutable
-  --> $DIR/suggestions.rs:46:13
+  --> $DIR/suggestions.rs:48:13
    |
-46 |         let mut a = (1); // should suggest no `mut`, no parens
-   |             ---^^
+48 |         let mut a = (1); // should suggest no `mut`, no parens
+   |             ----^
    |             |
    |             help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/suggestions.rs:11:9
+  --> $DIR/suggestions.rs:13:9
    |
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
    |         ^^^^^^^^^^
 
+warning: variable does not need to be mutable
+  --> $DIR/suggestions.rs:52:13
+   |
+52 |            let mut
+   |   _____________^
+   |  |_____________|
+   | ||
+53 | ||             b = 1;
+   | ||____________-^
+   |  |____________|
+   |               help: remove this `mut`
+
 warning: static is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:14:14
+  --> $DIR/suggestions.rs:16:14
    |
-14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+16 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
    |              -^^^^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              help: try making it public: `pub`
@@ -43,9 +55,9 @@ warning: static is marked #[no_mangle], but not exported
    = note: #[warn(private_no_mangle_statics)] on by default
 
 error: const items should never be #[no_mangle]
-  --> $DIR/suggestions.rs:16:14
+  --> $DIR/suggestions.rs:18:14
    |
-16 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+18 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
    |              -----^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              help: try a static value: `pub static`
@@ -53,19 +65,19 @@ error: const items should never be #[no_mangle]
    = note: #[deny(no_mangle_const_items)] on by default
 
 warning: functions generic over types must be mangled
-  --> $DIR/suggestions.rs:20:1
+  --> $DIR/suggestions.rs:22:1
    |
-19 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+21 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
    | ------------ help: remove this attribute
-20 | pub fn defiant<T>(_t: T) {}
+22 | pub fn defiant<T>(_t: T) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: #[warn(no_mangle_generic_items)] on by default
 
 warning: function is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:24:1
+  --> $DIR/suggestions.rs:26:1
    |
-24 | fn rio_grande() {} // should suggest `pub`
+26 | fn rio_grande() {} // should suggest `pub`
    | -^^^^^^^^^^^^^^^^^
    | |
    | help: try making it public: `pub`
@@ -73,29 +85,29 @@ warning: function is marked #[no_mangle], but not exported
    = note: #[warn(private_no_mangle_fns)] on by default
 
 warning: static is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:31:18
+  --> $DIR/suggestions.rs:33:18
    |
-31 |     #[no_mangle] pub static DAUNTLESS: bool = true;
+33 |     #[no_mangle] pub static DAUNTLESS: bool = true;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: function is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:33:18
+  --> $DIR/suggestions.rs:35:18
    |
-33 |     #[no_mangle] pub fn val_jean() {}
+35 |     #[no_mangle] pub fn val_jean() {}
    |                  ^^^^^^^^^^^^^^^^^^^^
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/suggestions.rs:44:5
+  --> $DIR/suggestions.rs:46:5
    |
-44 |     while true { // should suggest `loop`
+46 |     while true { // should suggest `loop`
    |     ^^^^^^^^^^ help: use `loop`
    |
    = note: #[warn(while_true)] on by default
 
 warning: the `warp_factor:` in this pattern is redundant
-  --> $DIR/suggestions.rs:51:23
+  --> $DIR/suggestions.rs:57:23
    |
-51 |             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+57 |             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
    |                       ------------^^^^^^^^^^^^
    |                       |
    |                       help: remove this
index 296b3b191e319e93ec0ddbf5c8ee7219401fcdee..982de00b4fa7c37ea89f6f4a500d3eb176423b98 100644 (file)
@@ -3,6 +3,10 @@ error[E0571]: `break` with value from a `for` loop
    |
 22 |         break 22 //~ ERROR `break` with value from a `for` loop
    |         ^^^^^^^^ can only break with a value inside `loop`
+help: instead, use `break` on its own without a value inside this `for` loop
+   |
+22 |         break //~ ERROR `break` with value from a `for` loop
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/span-covering-argument-1.rs b/src/test/ui/macros/span-covering-argument-1.rs
new file mode 100644 (file)
index 0000000..bfc137f
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2018 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_rules! bad {
+    ($s:ident whatever) => {
+        {
+            let $s = 0;
+            *&mut $s = 0;
+            //~^ ERROR cannot borrow immutable local variable `foo` as mutable [E0596]
+        }
+    }
+}
+
+fn main() {
+    bad!(foo whatever);
+}
diff --git a/src/test/ui/macros/span-covering-argument-1.stderr b/src/test/ui/macros/span-covering-argument-1.stderr
new file mode 100644 (file)
index 0000000..677d2f1
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0596]: cannot borrow immutable local variable `foo` as mutable
+  --> $DIR/span-covering-argument-1.rs:15:19
+   |
+14 |             let $s = 0;
+   |                 -- consider changing this to `mut $s`
+15 |             *&mut $s = 0;
+   |                   ^^ cannot borrow mutably
+...
+22 |     bad!(foo whatever);
+   |     ------------------- in this macro invocation
+
+error: aborting due to previous error
+
index e45616cd67a811419117cc16d6152700e250f66f..5144b59955cc9da6ef33a697fa9921df3de7470f 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 fn main() {
-    1 + Some(1); //~ ERROR is not satisfied
-    2 as usize - Some(1); //~ ERROR is not satisfied
-    3 * (); //~ ERROR is not satisfied
-    4 / ""; //~ ERROR is not satisfied
+    1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
+    2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
+    3 * (); //~ ERROR cannot multiply `()` to `{integer}`
+    4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
     5 < String::new(); //~ ERROR is not satisfied
     6 == Ok(1); //~ ERROR is not satisfied
 }
index 8541ad52e017759327d01e0292245baad00d2485..1b7fba050636f94e30891fb7f0916037ec214834 100644 (file)
@@ -1,31 +1,31 @@
-error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
+error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}`
   --> $DIR/binops.rs:12:7
    |
-12 |     1 + Some(1); //~ ERROR is not satisfied
+12 |     1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
    |       ^ no implementation for `{integer} + std::option::Option<{integer}>`
    |
    = help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
 
-error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
+error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize`
   --> $DIR/binops.rs:13:16
    |
-13 |     2 as usize - Some(1); //~ ERROR is not satisfied
+13 |     2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
    |                ^ no implementation for `usize - std::option::Option<{integer}>`
    |
    = help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
 
-error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
+error[E0277]: cannot multiply `()` to `{integer}`
   --> $DIR/binops.rs:14:7
    |
-14 |     3 * (); //~ ERROR is not satisfied
+14 |     3 * (); //~ ERROR cannot multiply `()` to `{integer}`
    |       ^ no implementation for `{integer} * ()`
    |
    = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`
 
-error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
+error[E0277]: cannot divide `{integer}` by `&str`
   --> $DIR/binops.rs:15:7
    |
-15 |     4 / ""; //~ ERROR is not satisfied
+15 |     4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
    |       ^ no implementation for `{integer} / &str`
    |
    = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
diff --git a/src/test/ui/on-unimplemented/auxiliary/no_debug.rs b/src/test/ui/on-unimplemented/auxiliary/no_debug.rs
new file mode 100644 (file)
index 0000000..0f833c6
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2018 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-tidy-linelength
+
+#![crate_type = "lib"]
+
+pub struct Bar;
diff --git a/src/test/ui/on-unimplemented/no-debug.rs b/src/test/ui/on-unimplemented/no-debug.rs
new file mode 100644 (file)
index 0000000..fff6122
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 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:no_debug.rs
+
+extern crate no_debug;
+
+use no_debug::Bar;
+
+struct Foo;
+
+fn main() {
+    println!("{:?} {:?}", Foo, Bar);
+    println!("{} {}", Foo, Bar);
+}
+//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug`
+//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug`
+//~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display`
+//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display`
+
diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr
new file mode 100644 (file)
index 0000000..af5b1e9
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0277]: `Foo` doesn't implement `std::fmt::Debug`
+  --> $DIR/no-debug.rs:20:27
+   |
+20 |     println!("{:?} {:?}", Foo, Bar);
+   |                           ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
+   |
+   = help: the trait `std::fmt::Debug` is not implemented for `Foo`
+   = note: required by `std::fmt::Debug::fmt`
+
+error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug`
+  --> $DIR/no-debug.rs:20:32
+   |
+20 |     println!("{:?} {:?}", Foo, Bar);
+   |                                ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar`
+   = note: required by `std::fmt::Debug::fmt`
+
+error[E0277]: `Foo` doesn't implement `std::fmt::Display`
+  --> $DIR/no-debug.rs:21:23
+   |
+21 |     println!("{} {}", Foo, Bar);
+   |                       ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `Foo`
+   = note: required by `std::fmt::Display::fmt`
+
+error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display`
+  --> $DIR/no-debug.rs:21:28
+   |
+21 |     println!("{} {}", Foo, Bar);
+   |                            ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar`
+   = note: required by `std::fmt::Display::fmt`
+
+error: aborting due to 4 previous errors
+
index 2a0e71e192c621cd64c228768e93ae9125da46a4..728cd12e2c6855c8648e8592244db856a4ffc5f7 100644 (file)
@@ -1,8 +1,8 @@
 warning: struct is never used: `S`
-  --> $DIR/macro-span-replacement.rs:17:9
+  --> $DIR/macro-span-replacement.rs:17:14
    |
 17 |         $b $a; //~ WARN struct is never used
-   |         ^^^^^^
+   |              ^
 ...
 22 |     m!(S struct);
    |     ------------- in this macro invocation
index f8e4cbcbf191f3a838bb5523b2f1cabe609d7d5f..dd09534480e10dde5247fedd7058cd6bd6ffb8d9 100644 (file)
@@ -20,7 +20,7 @@ fn main() {
     let x = 1;
     let y = 2;
     let z = 3;
-    foo(1 as u32 + //~ ERROR not satisfied
+    foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
 
         bar(x,
 
index b068798630ed8602c0cde87f89a2d49e31d369ca..a18dfeb31d9ef0bb86d4a2705bc19686a316d357 100644 (file)
@@ -1,7 +1,7 @@
-error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
+error[E0277]: cannot add `()` to `u32`
   --> $DIR/multiline-span-simple.rs:23:18
    |
-23 |     foo(1 as u32 + //~ ERROR not satisfied
+23 |     foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
    |                  ^ no implementation for `u32 + ()`
    |
    = help: the trait `std::ops::Add<()>` is not implemented for `u32`
index a99dbf21e54e20e27c903da045de13d8de243094..24ba27b27ad368623eab3eeaa7398348fa4c6589 100644 (file)
@@ -8,7 +8,7 @@ note: lifetime parameter instantiated with the lifetime 'a as defined on the imp
   --> $DIR/static-lifetime.rs:13:1
    |
 13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but lifetime parameter must outlive the static lifetime
 
 error: aborting due to previous error
index 7a6dc9a504029fb44b5c7d23d74b92bf31dd0a29..88a7b1b49d62d693d85991972b00cbdbd377f030 100644 (file)
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
   --> $DIR/for-c-in-str.rs:14:14
    |
 14 |     for c in "asdf" {
-   |              ^^^^^^ `&str` is not an iterator; maybe try calling `.iter()` or a similar method
+   |              ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
    |
    = help: the trait `std::iter::Iterator` is not implemented for `&str`
    = note: required by `std::iter::IntoIterator::into_iter`
index a9b6b3ee70d57cb4bddbdc5e07c41aee5286922a..0a68d34ade9faf2d1e85d5bf27226c46c15ef707 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(use_nested_groups)]
-
 mod a {
     pub mod b1 {
         pub enum C2 {}
index cae34684c8e38dbed173beffa83a32590740e9d7..c4edb626be0bb488c08b2144998de9598b60a144 100644 (file)
@@ -1,7 +1,7 @@
 error[E0432]: unresolved import `a::b1::C1`
-  --> $DIR/use-nested-groups-error.rs:21:14
+  --> $DIR/use-nested-groups-error.rs:19:14
    |
-21 | use a::{b1::{C1, C2}, B2};
+19 | use a::{b1::{C1, C2}, B2};
    |              ^^ no `C1` in `a::b1`. Did you mean to use `C2`?
 
 error: aborting due to previous error
index 7d7fef1690218bbb406cf3bcadf7bb29dbb40cc5..ce47e529d29f0bf19b31ae80b37b467e42fb97e2 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7d7fef1690218bbb406cf3bcadf7bb29dbb40cc5
+Subproject commit ce47e529d29f0bf19b31ae80b37b467e42fb97e2
index ff662736bdd1b7f004a5a178587cf4167243edc4..80750f9a3fee08081a8392829887462a6badc20c 100644 (file)
@@ -167,7 +167,7 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
                         .expect("Malformed llvm version directive");
                     // Ignore if using system LLVM and actual version
                     // is smaller the minimum required version
-                    !(config.system_llvm && &actual_version[..] < min_version)
+                    config.system_llvm && &actual_version[..] < min_version
                 } else {
                     false
                 }
index abf62a060b83b388f77c00a8c6f3d355891ebb27..46df211cbaf65f225df1c55278e5a3b39c51c5aa 100644 (file)
@@ -79,7 +79,7 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
     let mut results = Vec::new();
     let mut mismatch = Mismatch::new(0);
 
-    for result in diff::lines(actual, expected) {
+    for result in diff::lines(expected, actual) {
         match result {
             diff::Result::Left(str) => {
                 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
@@ -91,7 +91,8 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
                 }
 
-                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
+                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
+                line_number += 1;
                 lines_since_mismatch = 0;
             }
             diff::Result::Right(str) => {
@@ -104,8 +105,7 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
                 }
 
-                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
-                line_number += 1;
+                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
                 lines_since_mismatch = 0;
             }
             diff::Result::Both(str, _) => {
index 919604e1ead8294c8ca14f101be4380ea1ea370c..61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 919604e1ead8294c8ca14f101be4380ea1ea370c
+Subproject commit 61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d
index 511321ae1c2fa3f0e334885fecf406dd6c882836..dee42bda8156a28ead609080e27b02173bb9c29e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 511321ae1c2fa3f0e334885fecf406dd6c882836
+Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e
index bc35cbe9fbba64a3fbb2841f980be0511a515f0c..539b434e9eca554c9dc9d52a130e4d3dfbde28ef 100644 (file)
@@ -8,5 +8,5 @@ license = "MIT/Apache-2.0"
 clap = "2.25.0"
 
 [dependencies.mdbook]
-version = "0.0.28"
+version = "0.1.2"
 default-features = false
index 50f4364e448f73a8101aaf925c41e586c915716e..87a63a34cb642ef5c978cdb563fb3738a99be6a3 100644 (file)
@@ -13,7 +13,6 @@
 extern crate clap;
 
 use std::env;
-use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 
 use clap::{App, ArgMatches, SubCommand, AppSettings};
@@ -45,14 +44,19 @@ fn main() {
     };
 
     if let Err(e) = res {
-        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
+        eprintln!("Error: {}", e);
+
+        for cause in e.iter().skip(1) {
+            eprintln!("\tCaused By: {}", cause);
+        }
+
         ::std::process::exit(101);
     }
 }
 // Build command implementation
 pub fn build(args: &ArgMatches) -> Result<()> {
     let book_dir = get_book_dir(args);
-    let mut book = MDBook::new(&book_dir).read_config()?;
+    let mut book = MDBook::load(&book_dir)?;
 
     // Set this to allow us to catch bugs in advance.
     book.config.build.create_missing = false;
index e0e3e22248cd14ebbe0253e9720261a0328bfc59..346238f49740d6c98102a6a59811b1625c73a9d7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e0e3e22248cd14ebbe0253e9720261a0328bfc59
+Subproject commit 346238f49740d6c98102a6a59811b1625c73a9d7
index bc2767c7bcc5df4248006963b73ff93f6515b61a..159c9e035b7a28ab3e24d6bfb3536d580a54b97e 100644 (file)
@@ -33,6 +33,8 @@
     "openssl", // BSD+advertising clause, cargo, mdbook
     "pest", // MPL2, mdbook via handlebars
     "thread-id", // Apache-2.0, mdbook
+    "toml-query", // MPL-2.0, mdbook
+    "is-match", // MPL-2.0, mdbook
     "cssparser", // MPL-2.0, rustdoc
     "smallvec", // MPL-2.0, rustdoc
     "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo