]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #50638 - tbu-:pr_open_cloexec_once, r=nagisa
authorkennytm <kennytm@gmail.com>
Wed, 16 May 2018 15:22:45 +0000 (23:22 +0800)
committerGitHub <noreply@github.com>
Wed, 16 May 2018 15:22:45 +0000 (23:22 +0800)
Don't unconditionally set CLOEXEC twice on every fd we open on Linux

Previously, every `open64` was accompanied by a `ioctl(…, FIOCLEX)`,
because some old Linux version would ignore the `O_CLOEXEC` flag we pass
to the `open64` function.

Now, we check whether the `CLOEXEC` flag is set on the first file we
open – if it is, we won't do extra syscalls for every opened file. If it
is not set, we fall back to the old behavior of unconditionally calling
`ioctl(…, FIOCLEX)` on newly opened files.

On old Linuxes, this amounts to one extra syscall per process, namely
the `fcntl(…, F_GETFD)` call to check the `CLOEXEC` flag.

On new Linuxes, this reduces the number of syscalls per opened file by
one, except for the first file, where it does the same number of
syscalls as before (`fcntl(…, F_GETFD)` to check the flag instead of
`ioctl(…, FIOCLEX)` to set it).

445 files changed:
.travis.yml
appveyor.yml
src/Cargo.lock
src/bootstrap/bin/rustc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/tool.rs
src/ci/docker/disabled/dist-sparc64-linux/Dockerfile [new file with mode: 0644]
src/ci/docker/run.sh
src/ci/docker/x86_64-gnu-tools/checktools.sh
src/ci/docker/x86_64-gnu-tools/repo.sh
src/ci/shared.sh
src/doc/man/rustc.1
src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md [deleted file]
src/doc/unstable-book/src/language-features/macro-literal-matcher.md [new file with mode: 0644]
src/etc/generate-deriving-span-tests.py
src/liballoc/btree/map.rs
src/liballoc/btree/node.rs
src/liballoc/raw_vec.rs
src/liballoc/slice.rs
src/liballoc/str.rs
src/liballoc/tests/str.rs
src/liballoc/vec.rs
src/libcompiler_builtins
src/libcore/intrinsics.rs
src/libcore/iter/traits.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/ops/range.rs
src/libcore/ptr.rs
src/libcore/slice/mod.rs
src/libcore/str/mod.rs
src/libcore/tests/slice.rs
src/libcore/tests/str.rs
src/libcore/tests/time.rs
src/libcore/time.rs
src/libproc_macro/lib.rs
src/libproc_macro/quote.rs
src/librustc/cfg/construct.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/graph.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/itemlikevisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/hir/pat_util.rs
src/librustc/ich/fingerprint.rs
src/librustc/ich/impls_hir.rs
src/librustc/ich/impls_syntax.rs
src/librustc/ich/impls_ty.rs
src/librustc/infer/anon_types/mod.rs
src/librustc/infer/error_reporting/need_type_info.rs
src/librustc/infer/mod.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/middle/const_val.rs
src/librustc/middle/cstore.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/stability.rs
src/librustc/mir/interpret/mod.rs
src/librustc/mir/interpret/value.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/auto_trait.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/mod.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/on_unimplemented.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/structural_impls.rs
src/librustc/traits/util.rs
src/librustc/ty/codec.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/flags.rs
src/librustc/ty/fold.rs
src/librustc/ty/inhabitedness/mod.rs
src/librustc/ty/layout.rs
src/librustc/ty/maps/config.rs
src/librustc/ty/maps/keys.rs
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/plumbing.rs
src/librustc/ty/mod.rs
src/librustc/ty/relate.rs
src/librustc/ty/sty.rs
src/librustc/ty/subst.rs
src/librustc/ty/util.rs
src/librustc/util/ppaux.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/control_flow_graph/dominators/mod.rs
src/librustc_data_structures/lib.rs
src/librustc_data_structures/owning_ref/mod.rs
src/librustc_data_structures/sync.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_errors/lib.rs
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/work_product.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_llvm/ffi.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/interpret/const_eval.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/mod.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/item.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/simplify_branches.rs
src/librustc_mir/transform/uniform_array_move_out.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/pretty.rs
src/librustc_passes/ast_validation.rs
src/librustc_passes/loops.rs
src/librustc_privacy/lib.rs
src/librustc_save_analysis/Cargo.toml
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_target/abi/mod.rs
src/librustc_target/spec/aarch64_unknown_openbsd.rs [new file with mode: 0644]
src/librustc_target/spec/i686_unknown_openbsd.rs
src/librustc_target/spec/linux_musl_base.rs
src/librustc_target/spec/mod.rs
src/librustc_traits/dropck_outlives.rs
src/librustc_traits/lib.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/abi.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/symbol_export.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/builder.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/type_names.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/lib.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/coherence/builtin.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/impl_wf_check.rs
src/librustc_typeck/outlives/implicit_infer.rs
src/librustdoc/Cargo.toml
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/externalfiles.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/test.rs
src/librustdoc/theme.rs
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/fs.rs
src/libstd/path.rs
src/libstd/primitive_docs.rs
src/libstd/sys/redox/syscall/error.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys_common/wtf8.rs
src/libsyntax/attr.rs
src/libsyntax/edition.rs
src/libsyntax/ext/quote.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/deriving/cmp/partial_ord.rs
src/libsyntax_ext/format_foreign.rs
src/libsyntax_pos/Cargo.toml
src/libsyntax_pos/hygiene.rs
src/libsyntax_pos/lib.rs
src/libsyntax_pos/span_encoding.rs
src/libsyntax_pos/symbol.rs
src/llvm
src/rustllvm/PassWrapper.cpp
src/stdsimd
src/test/codegen/link_section.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_38586.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/issue-38586.rs
src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs
src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs
src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs [new file with mode: 0644]
src/test/compile-fail/coerce-to-bang.rs
src/test/compile-fail/cross-fn-cache-hole.rs
src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs
src/test/compile-fail/derives-span-PartialOrd-enum.rs
src/test/compile-fail/derives-span-PartialOrd-struct.rs
src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs
src/test/compile-fail/edition-extern-crate-allowed.rs [new file with mode: 0644]
src/test/compile-fail/edition-feature-ok.rs [new file with mode: 0644]
src/test/compile-fail/issue-42796.rs
src/test/compile-fail/range_traits-1.rs
src/test/run-make-fulldeps/issue-36710/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/issue-36710/foo.cpp [new file with mode: 0644]
src/test/run-make-fulldeps/issue-36710/foo.rs [new file with mode: 0644]
src/test/run-make-fulldeps/tools.mk
src/test/run-make/cross-lang-lto/Makefile
src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
src/test/run-pass-fulldeps/macro-quote-cond.rs
src/test/run-pass-fulldeps/macro-quote-test.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs
src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.rs
src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
src/test/run-pass-fulldeps/proc-macro/issue-39889.rs
src/test/run-pass-fulldeps/proc-macro/issue-40001.rs
src/test/run-pass-fulldeps/proc-macro/lifetimes.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/proc-macro/negative-token.rs
src/test/run-pass-fulldeps/proc-macro/span-api-tests.rs
src/test/run-pass/atomic-print.rs
src/test/run-pass/impl-trait/issue-49376.rs [new file with mode: 0644]
src/test/run-pass/issue-46845.rs
src/test/run-pass/issue-49298.rs [new file with mode: 0644]
src/test/run-pass/issue-50442.rs [new file with mode: 0644]
src/test/run-pass/issue-50731.rs [new file with mode: 0644]
src/test/run-pass/macro-lifetime-used-with-bound.rs
src/test/run-pass/macro-lifetime-used-with-labels.rs
src/test/run-pass/macro-lifetime-used-with-static.rs
src/test/run-pass/macro-lifetime.rs
src/test/run-pass/macro-literal.rs [new file with mode: 0644]
src/test/run-pass/type-sizes.rs
src/test/run-pass/union/union-trait-impl.rs
src/test/rustdoc-js/deduplication.js [new file with mode: 0644]
src/test/rustdoc/pub-restricted.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/invalid-punct-ident.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/lifetimes.rs [new file with mode: 0644]
src/test/ui-fulldeps/custom-derive/auxiliary/plugin.rs
src/test/ui-fulldeps/custom-derive/issue-36935.rs
src/test/ui-fulldeps/custom-derive/issue-36935.stderr
src/test/ui-fulldeps/invalid-punct-ident-1.rs [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-1.stderr [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-2.rs [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-2.stderr [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-3.rs [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-3.stderr [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-4.rs [new file with mode: 0644]
src/test/ui-fulldeps/invalid-punct-ident-4.stderr [new file with mode: 0644]
src/test/ui-fulldeps/lifetimes.rs [new file with mode: 0644]
src/test/ui-fulldeps/lifetimes.stderr [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
src/test/ui-fulldeps/proc-macro/parent-source-spans.rs
src/test/ui-fulldeps/proc-macro/three-equals.rs
src/test/ui-fulldeps/resolve-error.rs
src/test/ui-fulldeps/resolve-error.stderr
src/test/ui-fulldeps/unnecessary-extern-crate.rs
src/test/ui-fulldeps/unnecessary-extern-crate.stderr
src/test/ui/binary-op-on-double-ref.stderr
src/test/ui/codemap_tests/issue-28308.stderr
src/test/ui/const-eval/duration_conversion.rs [new file with mode: 0644]
src/test/ui/error-codes/E0067.stderr
src/test/ui/error-codes/E0600.stderr
src/test/ui/error-festival.stderr
src/test/ui/feature-gate-macro-lifetime-matcher.rs [deleted file]
src/test/ui/feature-gate-macro-lifetime-matcher.stderr [deleted file]
src/test/ui/feature-gate-macro-literal-matcher.rs [new file with mode: 0644]
src/test/ui/feature-gate-macro-literal-matcher.stderr [new file with mode: 0644]
src/test/ui/feature-gate-negate-unsigned.stderr
src/test/ui/feature-gate-trivial_bounds-lint.rs [new file with mode: 0644]
src/test/ui/feature-gate-trivial_bounds.rs [new file with mode: 0644]
src/test/ui/feature-gate-trivial_bounds.stderr [new file with mode: 0644]
src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr [deleted file]
src/test/ui/issue-3008-1.stderr
src/test/ui/issue-32326.stderr
src/test/ui/issue-48728.stderr
src/test/ui/issue-50480.rs [new file with mode: 0644]
src/test/ui/issue-50480.stderr [new file with mode: 0644]
src/test/ui/issue-50618.rs [new file with mode: 0644]
src/test/ui/issue-50618.stderr [new file with mode: 0644]
src/test/ui/issue-5239-1.stderr
src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs
src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr
src/test/ui/lint/unreachable_pub-pub_crate.rs
src/test/ui/lint/unreachable_pub-pub_crate.stderr
src/test/ui/lint/unreachable_pub.rs
src/test/ui/lint/unreachable_pub.stderr
src/test/ui/macro-invalid-fragment-spec.stderr
src/test/ui/macros/nonterminal-matching.rs
src/test/ui/on-unimplemented/bad-annotation.rs
src/test/ui/on-unimplemented/bad-annotation.stderr
src/test/ui/reachable/expr_unary.stderr
src/test/ui/rfc-2093-infer-outlives/enum.rs
src/test/ui/rfc-2093-infer-outlives/enum.stderr
src/test/ui/rfc1598-generic-associated-types/collections.rs [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/collections.stderr [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs
src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr
src/test/ui/rfc1598-generic-associated-types/iterable.rs
src/test/ui/rfc1598-generic-associated-types/iterable.stderr
src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/shadowing.rs [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/shadowing.stdout [new file with mode: 0644]
src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs
src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr
src/test/ui/single-use-lifetime/fn-types.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/fn-types.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-struct.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-fn.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-impl.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr [new file with mode: 0644]
src/test/ui/span/E0204.stderr
src/test/ui/span/issue-42234-unknown-receiver-type.stderr
src/test/ui/span/method-and-field-eager-resolution.rs [new file with mode: 0644]
src/test/ui/span/method-and-field-eager-resolution.stderr [new file with mode: 0644]
src/test/ui/suggestions/auxiliary/removing-extern-crate.rs [new file with mode: 0644]
src/test/ui/suggestions/removing-extern-crate.fixed [new file with mode: 0644]
src/test/ui/suggestions/removing-extern-crate.rs [new file with mode: 0644]
src/test/ui/suggestions/removing-extern-crate.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-associated-functions.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-associated-functions.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-copy.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-copy.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-sized.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-sized.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-well-formed.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent-well-formed.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-inconsistent.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-leak-copy.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-leak-copy.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-leak.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-leak.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds-lint.rs [new file with mode: 0644]
src/test/ui/trivial-bounds-lint.stderr [new file with mode: 0644]
src/test/ui/type-check/missing_trait_impl.rs
src/test/ui/type-check/missing_trait_impl.stderr
src/test/ui/union/union-sized-field.stderr
src/test/ui/unsized-enum2.stderr
src/test/ui/update-references.sh
src/tools/clippy
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/rls
src/tools/rustdoc-js/tester.js
src/tools/rustfmt
src/tools/tidy/src/deps.rs
src/tools/tidy/src/libcoretest.rs

index 23c47bc9f7648199848b65a90d1abc71461c9047..9e62b895ed21eaa17a717a2c7508b75af055b57d 100644 (file)
@@ -197,7 +197,7 @@ env:
     # AWS_SECRET_ACCESS_KEY=...
     - secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo="
     # TOOLSTATE_REPO_ACCESS_TOKEN=...
-    - secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk="
+    - secure: "ESfcXqv4N2VMhqi2iIyw6da9VrsA78I4iR1asouCaq4hzTTrkB4WNRrfURy6xg72gQ4nMhtRJbB0/2jmc9Cu1+g2CzXtyiL223aJ5CKrXdcvbitopQSDfp07dMWm+UED+hNFEanpErKAeU/6FM3A+J+60PMk8MCF1h9tqNRISJw="
 
 before_install:
   # We'll use the AWS cli to download/upload cached docker layers, so install
index a92f4a17811814a95f07f2a7b55efd0578804bf5..b1e2e1545cf85042f1950274249303a2763f5846 100644 (file)
@@ -6,7 +6,7 @@ environment:
     secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80
   SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c
   TOOLSTATE_REPO_ACCESS_TOKEN:
-    secure: PTZiSxJMVUZ0VnMR5i13E4OagbXfglj7pcskDQiKufVrDm13mLoI0vDJAEM35+bY
+    secure: gKGlVktr7iuqCoYSxHxDE9ltLOKU0nYDEuQxvWbNxUIW7ri5ppn8L06jQzN0GGzN
 
   # By default schannel checks revocation of certificates unlike some other SSL
   # backends, but we've historically had problems on CI where a revocation
@@ -211,6 +211,11 @@ test_script:
   - set NO_CCACHE=1
   - sh src/ci/run.sh
 
+on_failure:
+  # Dump crash log
+  - set PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\Debuggers\X64"
+  - if exist %LOCALAPPDATA%\CrashDumps for %%f in (%LOCALAPPDATA%\CrashDumps\*) do cdb -c "k;q" -G -z "%%f"
+
 branches:
   only:
     - auto
index e2a9a6efbdad4fc855a0794e2c748903ff1cef17..210199df11c9edefe1dbd2b0e70041f6767240e3 100644 (file)
@@ -79,15 +79,15 @@ dependencies = [
 
 [[package]]
 name = "assert_cli"
-version = "0.5.4"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -183,11 +183,6 @@ dependencies = [
 name = "build_helper"
 version = "0.1.0"
 
-[[package]]
-name = "bytecount"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "byteorder"
 version = "1.2.2"
@@ -233,25 +228,13 @@ dependencies = [
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "cargo_metadata"
-version = "0.3.3"
-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)",
- "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "cargo_metadata"
 version = "0.5.4"
@@ -305,15 +288,17 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.0.197"
+version = "0.0.200"
 dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.200",
  "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (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.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -325,7 +310,7 @@ version = "0.2.0"
 
 [[package]]
 name = "clippy_lints"
-version = "0.0.197"
+version = "0.0.200"
 dependencies = [
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -334,7 +319,7 @@ dependencies = [
  "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -417,7 +402,7 @@ dependencies = [
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -551,12 +536,12 @@ version = "0.1.0"
 
 [[package]]
 name = "derive-new"
-version = "0.5.2"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -564,11 +549,6 @@ name = "diff"
 version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "difference"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "difference"
 version = "2.0.0"
@@ -999,7 +979,7 @@ dependencies = [
 
 [[package]]
 name = "languageserver-types"
-version = "0.39.0"
+version = "0.41.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)",
@@ -1169,7 +1149,7 @@ dependencies = [
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1187,6 +1167,14 @@ name = "memoffset"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "minifier"
+version = "0.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "miniz-sys"
 version = "0.1.10"
@@ -1429,14 +1417,6 @@ dependencies = [
  "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "proc-macro2"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "proc-macro2"
 version = "0.3.6"
@@ -1488,14 +1468,6 @@ name = "quote"
 version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "quote"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "quote"
 version = "0.5.1"
@@ -1601,6 +1573,18 @@ dependencies = [
  "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "regex"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "regex-syntax"
 version = "0.5.5"
@@ -1609,6 +1593,14 @@ dependencies = [
  "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "regex-syntax"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "remote-test-client"
 version = "0.1.0"
@@ -1627,28 +1619,28 @@ dependencies = [
 
 [[package]]
 name = "rls"
-version = "0.127.0"
+version = "0.128.0"
 dependencies = [
  "cargo 0.28.0",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.200",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "languageserver-types 0.41.0 (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)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-rustc 0.2.2 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.6.1",
+ "rustfmt-nightly 0.7.0",
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1657,13 +1649,13 @@ dependencies = [
 
 [[package]]
 name = "rls-analysis"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1675,7 +1667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rls-data"
-version = "0.15.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1743,17 +1735,16 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_cratesio_shim"
-version = "113.0.0"
+version = "128.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)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "113.0.0"
+version = "128.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)",
@@ -1761,68 +1752,63 @@ dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.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 = "113.0.0"
+version = "128.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "termcolor 0.3.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-rustc_target"
-version = "113.0.0"
+version = "128.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 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-ap-serialize"
-version = "113.0.0"
+version = "128.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rustc-ap-syntax"
-version = "113.0.0"
+version = "128.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_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.1 (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 = "113.0.0"
+version = "128.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.1 (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)",
 ]
 
@@ -1839,6 +1825,27 @@ dependencies = [
  "rustc_target 0.0.0",
 ]
 
+[[package]]
+name = "rustc-rayon"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-rayon-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rustc-serialize"
 version = "0.3.24"
@@ -1906,6 +1913,7 @@ dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_cratesio_shim 0.0.0",
  "serialize 0.0.0",
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1921,6 +1929,7 @@ dependencies = [
  "graphviz 0.0.0",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
  "rustc_borrowck 0.0.0",
  "rustc_data_structures 0.0.0",
@@ -1938,6 +1947,7 @@ dependencies = [
  "rustc_traits 0.0.0",
  "rustc_trans_utils 0.0.0",
  "rustc_typeck 0.0.0",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
  "syntax 0.0.0",
  "syntax_ext 0.0.0",
@@ -2111,7 +2121,7 @@ name = "rustc_save_analysis"
 version = "0.0.0"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2149,6 +2159,7 @@ dependencies = [
 name = "rustc_trans"
 version = "0.0.0"
 dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2218,10 +2229,19 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
+[[package]]
+name = "rustc_version"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
+ "minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2250,11 +2270,11 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "0.6.1"
+version = "0.7.0"
 dependencies = [
- "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2263,9 +2283,9 @@ dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2275,15 +2295,6 @@ dependencies = [
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "same-file"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "same-file"
 version = "1.0.2"
@@ -2311,15 +2322,6 @@ name = "scopeguard"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "semver"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "semver"
 version = "0.9.0"
@@ -2397,21 +2399,6 @@ name = "siphasher"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "skeptic"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "smallvec"
 version = "0.6.0"
@@ -2522,16 +2509,6 @@ dependencies = [
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "syn"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "syn"
 version = "0.13.1"
@@ -2590,6 +2567,7 @@ dependencies = [
 name = "syntax_pos"
 version = "0.0.0"
 dependencies = [
+ "arena 0.0.0",
  "rustc_data_structures 0.0.0",
  "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
@@ -2654,7 +2632,7 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.0.1"
+version = "3.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2915,16 +2893,6 @@ name = "void"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "walkdir"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "walkdir"
 version = "2.1.4"
@@ -3002,7 +2970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
-"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
+"checksum assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da59dbd8df54562665b925b427221ceda9b771408cb8a6cbd2125d3b001330b"
 "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
 "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
 "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
@@ -3010,9 +2978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
 "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
 "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
-"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
 "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
 "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
@@ -3033,9 +2999,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
 "checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a"
 "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
-"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
+"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
 "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
-"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
@@ -3080,7 +3045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
 "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4cdd5e52d71aca47050e5b25f03082609c63a1e76b7362ebdd010895b3f854"
+"checksum languageserver-types 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "017cf5ade4be5ebeb06277ccd281c268dbd2e0801128d3992b4b4057f34dd432"
 "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
 "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
 "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
@@ -3099,6 +3064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "26f3e36a4db1981b16567e4abfd6ddc3641bc9b950bdc868701f656bf9b74bdd"
 "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
 "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d"
 "checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa"
@@ -3126,13 +3092,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
-"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
 "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
 "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
 "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
-"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
 "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
 "checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
 "checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
@@ -3143,30 +3107,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
 "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
+"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
 "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
+"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
 "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
+"checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e"
 "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
-"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510"
+"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988"
 "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
 "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
 "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
-"checksum rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a01334797c5c4cf56cc40bb9636d7b4c4a076665b9b9b7f100fd666cf0a02ffc"
-"checksum rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03d6f8f7da0de905f6ef80dc14dce3bbc372430622b6aeb421cf13190bc70e8a"
-"checksum rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfd6183804a685c48601651d8c8c7b0daa8f83b0b5e24edfbcb6a0337085127"
-"checksum rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f223157f51bf0e0621bef099de862468892ee4c4b83056f48f63e1bc00ccb72"
-"checksum rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2104a55a87d65cba8a845656f1f19a35da52af403863cd2a4bd5876ba522d879"
-"checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323"
-"checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63"
+"checksum rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7374a2b466e6e3ce489e045302e304849355faf7fd033d4d95e6e86e48c313b4"
+"checksum rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b3c3e566868a04735852eb333db958453a53cacdd935fe508e0c9fd822ea88"
+"checksum rustc-ap-rustc_errors 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b81dc5e8a8e63befb0eaf1c9443e269dee6f8daced4e3149fe8a80947fd682e"
+"checksum rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6bb7f1df7a4ca231cbe35a5eaebdc22cd2258c0393e856513b5186dec720e4"
+"checksum rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1ab72257c28395c45a27a5812d94515ec43e639add4820eafc919a71c1714c3"
+"checksum rustc-ap-syntax 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf9ca2901388714e9ccc7de7281ef06cec55d9f245252ba1d635bc86c730d9a"
+"checksum rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5217444369a36e98e11f4ac976f03878704893832e2e0b57d49f2f31438139f"
 "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
+"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99"
+"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a"
 "checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85"
-"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
 "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
 "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
 "checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
-"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248"
@@ -3177,7 +3144,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
 "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 skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
 "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
 "checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
 "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
@@ -3188,7 +3154,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
 "checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
-"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
 "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
 "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
@@ -3197,7 +3162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
 "checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18"
 "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c"
+"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
 "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
 "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
 "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
@@ -3227,7 +3192,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
 "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
index 3f97accaa4d84088ecbd8524e359d653dda4aa6c..76d0e6e28aeda75e779ea703e8563dc01e2b4004 100644 (file)
@@ -268,6 +268,15 @@ fn main() {
         if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
             cmd.arg(format!("-Clinker={}", host_linker));
         }
+
+        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
+            if s == "true" {
+                cmd.arg("-C").arg("target-feature=+crt-static");
+            }
+            if s == "false" {
+                cmd.arg("-C").arg("target-feature=-crt-static");
+            }
+        }
     }
 
     if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
index 487440becf630de7471c0228bab09c014e33d2ac..28f5192f2cdf455d9e6730f64ce324ab679a8af5 100644 (file)
@@ -489,7 +489,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, self.build, "stage0")
 
-    def get_toml(self, key):
+    def get_toml(self, key, section=None):
         """Returns the value of the given key in config.toml, otherwise returns None
 
         >>> rb = RustBuild()
@@ -501,12 +501,29 @@ class RustBuild(object):
 
         >>> rb.get_toml("key3") is None
         True
+
+        Optionally also matches the section the key appears in
+
+        >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
+        >>> rb.get_toml('key', 'a')
+        'value1'
+        >>> rb.get_toml('key', 'b')
+        'value2'
+        >>> rb.get_toml('key', 'c') is None
+        True
         """
+
+        cur_section = None
         for line in self.config_toml.splitlines():
+            section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
+            if section_match is not None:
+                cur_section = section_match.group(1)
+
             match = re.match(r'^{}\s*=(.*)$'.format(key), line)
             if match is not None:
                 value = match.group(1)
-                return self.get_string(value) or value.strip()
+                if section is None or section == cur_section:
+                    return self.get_string(value) or value.strip()
         return None
 
     def cargo(self):
@@ -589,7 +606,17 @@ class RustBuild(object):
         env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
             (os.pathsep + env["LIBRARY_PATH"]) \
             if "LIBRARY_PATH" in env else ""
-        env["RUSTFLAGS"] = "-Cdebuginfo=2"
+        env["RUSTFLAGS"] = "-Cdebuginfo=2 "
+
+        build_section = "target.{}".format(self.build_triple())
+        target_features = []
+        if self.get_toml("crt-static", build_section) == "true":
+            target_features += ["+crt-static"]
+        elif self.get_toml("crt-static", build_section) == "false":
+            target_features += ["-crt-static"]
+        if target_features:
+            env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
+
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
             os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
index f87436504c6c62a03cab9a5705fb989f82bdf255..17f19222e6ea65637828e5cae38dbb0ab8e604d2 100644 (file)
@@ -690,6 +690,10 @@ pub fn cargo(&self,
             cargo.env("RUSTC_CRT_STATIC", x.to_string());
         }
 
+        if let Some(x) = self.crt_static(compiler.host) {
+            cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
+        }
+
         // Enable usage of unstable features
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
index 220af6bd6e4af02b7c8df1f64a7f427379b1c1ab..4b6e266f1e55c5ec35c60fc1370be789a1b97740 100644 (file)
@@ -556,15 +556,6 @@ fn run(mut $sel, $builder: &Builder) -> Option<PathBuf> {
     };
     Miri, miri, "src/tools/miri", "miri", {};
     Rls, rls, "src/tools/rls", "rls", {
-        let clippy = builder.ensure(Clippy {
-            compiler: self.compiler,
-            target: self.target,
-            extra_features: Vec::new(),
-        });
-        let channel = &builder.config.channel;
-        if clippy.is_some() && channel != "stable" && channel != "beta" {
-            self.extra_features.push("clippy".to_owned());
-        }
         builder.ensure(native::Openssl {
             target: self.target,
         });
diff --git a/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile
new file mode 100644 (file)
index 0000000..952c265
--- /dev/null
@@ -0,0 +1,26 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  g++-sparc64-linux-gnu \
+  libssl-dev \
+  pkg-config
+
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV HOSTS=sparc64-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
index c470ae7eb30306cdaa081c06e3c5d79e4d3b90c3..3465e386cd925c90c188a7cd27cd009c368c8beb 100755 (executable)
@@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
       url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
       echo "Attempting to download $s3url"
+      rm -f /tmp/rustci_docker_cache
       set +e
-      loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/')
+      retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url"
+      loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
       set -e
       echo "Downloaded containers:\n$loaded_images"
     fi
index 3fed0175371a7d494ec1d1bdaf790a7e73b4588d..d71d5daf8113bf4abb59d51101467e85985fc250 100755 (executable)
@@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
 
 touch "$TOOLSTATE_FILE"
 
+# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
+
 set +e
 python2.7 "$X_PY" test --no-fail-fast \
     src/doc/book \
@@ -38,6 +40,7 @@ set -e
 cat "$TOOLSTATE_FILE"
 echo
 
+# This function checks that if a tool's submodule changed, the tool's state must improve
 verify_status() {
     echo "Verifying status of $1..."
     if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
@@ -57,17 +60,36 @@ verify_status() {
     fi
 }
 
+# deduplicates the submodule check and the assertion that on beta some tools MUST be passing
+check_dispatch() {
+    if [ "$1" = submodule_changed ]; then
+        # ignore $2 (branch id)
+        verify_status $3 $4
+    elif [ "$2" = beta ]; then
+        echo "Requiring test passing for $3..."
+        if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then
+            exit 4
+        fi
+    fi
+}
+
+# list all tools here
+status_check() {
+    check_dispatch $1 beta book src/doc/book
+    check_dispatch $1 beta nomicon src/doc/nomicon
+    check_dispatch $1 beta reference src/doc/reference
+    check_dispatch $1 beta rust-by-example src/doc/rust-by-example
+    check_dispatch $1 beta rls src/tool/rls
+    check_dispatch $1 beta rustfmt src/tool/rustfmt
+    # these tools are not required for beta to successfully branch
+    check_dispatch $1 nightly clippy-driver src/tool/clippy
+    check_dispatch $1 nightly miri src/tool/miri
+}
+
 # If this PR is intended to update one of these tools, do not let the build pass
 # when they do not test-pass.
 
-verify_status book src/doc/book
-verify_status nomicon src/doc/nomicon
-verify_status reference src/doc/reference
-verify_status rust-by-example src/doc/rust-by-example
-verify_status rls src/tool/rls
-verify_status rustfmt src/tool/rustfmt
-verify_status clippy-driver src/tool/clippy
-verify_status miri src/tool/miri
+status_check "submodule_changed"
 
 if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
     . "$(dirname $0)/repo.sh"
@@ -86,6 +108,6 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE")
     exit 0
 fi
 
-if grep -q fail "$TOOLSTATE_FILE"; then
-    exit 4
-fi
+# abort compilation if an important tool doesn't build
+# (this code is reachable if not on the nightly channel)
+status_check "beta_required"
index c10afef753e810e25f62126927ba739c49b10381..807e6fb7b642e2d6b789ea7ef40aaf7c07633a88 100644 (file)
@@ -60,7 +60,7 @@ commit_toolstate_change() {
     OLDFLAGS="$-"
     set -eu
 
-    git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com'
+    git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com'
     git config --global user.name 'Rust Toolstate Update'
     git config --global credential.helper store
     printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \
index 4a08683e3ee86511f505d16a88f00b39d3a2fe5d..bb6945f0fd6bbb5b542778b466c532e8d3682c23 100644 (file)
@@ -21,11 +21,12 @@ function retry {
   while true; do
     "$@" && break || {
       if [[ $n -lt $max ]]; then
+        sleep $n  # don't retry immediately
         ((n++))
         echo "Command failed. Attempt $n/$max:"
       else
         echo "The command has failed after $n attempts."
-        exit 1
+        return 1
       fi
     }
   done
index 39d105399594535a5f0885e67369a796f918e696..8f611063dbe5d901a222b5fb45134965d0ab319e 100644 (file)
@@ -55,7 +55,7 @@ Configure the output that \fBrustc\fR will produce. Each emission may also have
 an optional explicit output \fIPATH\fR specified for that particular emission
 kind. This path takes precedence over the \fB-o\fR option.
 .TP
-\fB\-\-print\fR [crate\-name|file\-names|sysroot]
+\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs]
 Comma separated list of compiler information to print on stdout.
 .TP
 \fB\-g\fR
diff --git a/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md b/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md
deleted file mode 100644 (file)
index 5b585d7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# `macro_lifetime_matcher`
-
-The tracking issue for this feature is: [#46895]
-
-With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry:
-
-* `lifetime`: a lifetime. Examples: 'static, 'a.
-
-A `lifetime` variable may be followed by anything.
-
-[#46895]: https://github.com/rust-lang/rust/issues/46895
-[frags]: ../book/first-edition/macros.html#syntactic-requirements
-
-------------------------
diff --git a/src/doc/unstable-book/src/language-features/macro-literal-matcher.md b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md
new file mode 100644 (file)
index 0000000..7e3638f
--- /dev/null
@@ -0,0 +1,17 @@
+# `macro_literal_matcher`
+
+The tracking issue for this feature is: [#35625]
+
+The RFC is: [rfc#1576].
+
+With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry:
+
+* `literal`: a literal. Examples: 2, "string", 'c'
+
+A `literal` may be followed by anything, similarly to the `ident` specifier.
+
+[rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html
+[#35625]: https://github.com/rust-lang/rust/issues/35625
+[frags]: ../book/first-edition/macros.html#syntactic-requirements
+
+------------------------
index edb9389c00c58e0b3410bcb74d1e125581b3629b..2e9169ce5b942920c16dc5426003888fd98ec8b7 100755 (executable)
@@ -122,7 +122,7 @@ traits = {
 
 for (trait, supers, errs) in [('Clone', [], 1),
                               ('PartialEq', [], 2),
-                              ('PartialOrd', ['PartialEq'], 5),
+                              ('PartialOrd', ['PartialEq'], 1),
                               ('Eq', ['PartialEq'], 1),
                               ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1),
                               ('Debug', [], 1),
index 3984379ea860dd3eabbb099da3c691cb78fcab61..bb2c68a27ba308f3ba1e825d57bbabd678e20cc4 100644 (file)
@@ -246,6 +246,7 @@ fn take(&mut self, key: &Q) -> Option<K> {
     }
 
     fn replace(&mut self, key: K) -> Option<K> {
+        self.ensure_root_is_owned();
         match search::search_tree::<marker::Mut, K, (), K>(self.root.as_mut(), &key) {
             Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
             GoDown(handle) => {
@@ -523,7 +524,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> BTreeMap<K, V> {
         BTreeMap {
-            root: node::Root::new_leaf(),
+            root: node::Root::shared_empty_root(),
             length: 0,
         }
     }
@@ -544,7 +545,6 @@ pub fn new() -> BTreeMap<K, V> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
-        // FIXME(gereeter) .clear() allocates
         *self = BTreeMap::new();
     }
 
@@ -890,6 +890,8 @@ pub fn range_mut<T: ?Sized, R>(&mut self, range: R) -> RangeMut<K, V>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn entry(&mut self, key: K) -> Entry<K, V> {
+        // FIXME(@porglezomp) Avoid allocating if we don't insert
+        self.ensure_root_is_owned();
         match search::search_tree(self.root.as_mut(), &key) {
             Found(handle) => {
                 Occupied(OccupiedEntry {
@@ -910,6 +912,7 @@ pub fn entry(&mut self, key: K) -> Entry<K, V> {
     }
 
     fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
+        self.ensure_root_is_owned();
         let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
         // Iterate through all key-value pairs, pushing them into nodes at the right level.
         for (key, value) in iter {
@@ -1019,6 +1022,7 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
         let total_num = self.len();
 
         let mut right = Self::new();
+        right.root = node::Root::new_leaf();
         for _ in 0..(self.root.as_ref().height()) {
             right.root.push_level();
         }
@@ -1153,6 +1157,13 @@ fn fix_left_border(&mut self) {
 
         self.fix_top();
     }
+
+    /// If the root node is the shared root node, allocate our own node.
+    fn ensure_root_is_owned(&mut self) {
+        if self.root.is_shared_root() {
+            self.root = node::Root::new_leaf();
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1290,6 +1301,10 @@ fn drop(&mut self) {
         self.for_each(drop);
         unsafe {
             let leaf_node = ptr::read(&self.front).into_node();
+            if leaf_node.is_shared_root() {
+                return;
+            }
+
             if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
                 let mut cur_node = first_parent.into_node();
                 while let Some(parent) = cur_node.deallocate_and_ascend() {
index d6346662314e65ae993a498ff4ffba1fb9579f30..431695c32ab68f8f9d35bef16a9442cb6a35d5cb 100644 (file)
 ///
 /// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
 /// avoiding accidentally dropping unused and uninitialized keys and values.
+///
+/// We put the metadata first so that its position is the same for every `K` and `V`, in order
+/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
+/// prevent them from being reordered.
+#[repr(C)]
 struct LeafNode<K, V> {
-    /// The arrays storing the actual data of the node. Only the first `len` elements of each
-    /// array are initialized and valid.
-    keys: [K; CAPACITY],
-    vals: [V; CAPACITY],
-
     /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
     /// This either points to an actual node or is null.
     parent: *const InternalNode<K, V>,
@@ -77,10 +77,14 @@ struct LeafNode<K, V> {
 
     /// The number of keys and values this node stores.
     ///
-    /// This is at the end of the node's representation and next to `parent_idx` to encourage
-    /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space
-    /// overhead.
+    /// This next to `parent_idx` to encourage the compiler to join `len` and
+    /// `parent_idx` into the same 32-bit word, reducing space overhead.
     len: u16,
+
+    /// The arrays storing the actual data of the node. Only the first `len` elements of each
+    /// array are initialized and valid.
+    keys: [K; CAPACITY],
+    vals: [V; CAPACITY],
 }
 
 impl<K, V> LeafNode<K, V> {
@@ -97,8 +101,26 @@ unsafe fn new() -> Self {
             len: 0
         }
     }
+
+    fn is_shared_root(&self) -> bool {
+        self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V>
+    }
 }
 
+// We need to implement Sync here in order to make a static instance.
+unsafe impl Sync for LeafNode<(), ()> {}
+
+// An empty node used as a placeholder for the root node, to avoid allocations.
+// We use () in order to save space, since no operation on an empty tree will
+// ever take a pointer past the first key.
+static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
+    parent: ptr::null(),
+    parent_idx: 0,
+    len: 0,
+    keys: [(); CAPACITY],
+    vals: [(); CAPACITY],
+};
+
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
 /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
 /// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
@@ -168,6 +190,21 @@ unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> { }
 unsafe impl<K: Send, V: Send> Send for Root<K, V> { }
 
 impl<K, V> Root<K, V> {
+    pub fn is_shared_root(&self) -> bool {
+        self.as_ref().is_shared_root()
+    }
+
+    pub fn shared_empty_root() -> Self {
+        Root {
+            node: unsafe {
+                BoxedNode::from_ptr(NonNull::new_unchecked(
+                    &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> as *mut _
+                ))
+            },
+            height: 0,
+        }
+    }
+
     pub fn new_leaf() -> Self {
         Root {
             node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),
@@ -209,6 +246,7 @@ pub fn into_ref(self)
     /// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
     pub fn push_level(&mut self)
             -> NodeRef<marker::Mut, K, V, marker::Internal> {
+        debug_assert!(!self.is_shared_root());
         let mut new_node = Box::new(unsafe { InternalNode::new() });
         new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) };
 
@@ -353,12 +391,16 @@ fn as_leaf(&self) -> &LeafNode<K, V> {
         }
     }
 
+    pub fn is_shared_root(&self) -> bool {
+        self.as_leaf().is_shared_root()
+    }
+
     pub fn keys(&self) -> &[K] {
-        self.reborrow().into_slices().0
+        self.reborrow().into_key_slice()
     }
 
-    pub fn vals(&self) -> &[V] {
-        self.reborrow().into_slices().1
+    fn vals(&self) -> &[V] {
+        self.reborrow().into_val_slice()
     }
 
     /// Finds the parent of the current node. Returns `Ok(handle)` if the current
@@ -433,6 +475,7 @@ pub unsafe fn deallocate_and_ascend(self) -> Option<
             marker::Edge
         >
     > {
+        debug_assert!(!self.is_shared_root());
         let node = self.node;
         let ret = self.ascend().ok();
         Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
@@ -500,30 +543,51 @@ fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
         }
     }
 
-    pub fn keys_mut(&mut self) -> &mut [K] {
-        unsafe { self.reborrow_mut().into_slices_mut().0 }
+    fn keys_mut(&mut self) -> &mut [K] {
+        unsafe { self.reborrow_mut().into_key_slice_mut() }
     }
 
-    pub fn vals_mut(&mut self) -> &mut [V] {
-        unsafe { self.reborrow_mut().into_slices_mut().1 }
+    fn vals_mut(&mut self) -> &mut [V] {
+        unsafe { self.reborrow_mut().into_val_slice_mut() }
     }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    pub fn into_slices(self) -> (&'a [K], &'a [V]) {
-        unsafe {
-            (
+    fn into_key_slice(self) -> &'a [K] {
+        // When taking a pointer to the keys, if our key has a stricter
+        // alignment requirement than the shared root does, then the pointer
+        // would be out of bounds, which LLVM assumes will not happen. If the
+        // alignment is more strict, we need to make an empty slice that doesn't
+        // use an out of bounds pointer.
+        if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+            &[]
+        } else {
+            // Here either it's not the root, or the alignment is less strict,
+            // in which case the keys pointer will point "one-past-the-end" of
+            // the node, which is allowed by LLVM.
+            unsafe {
                 slice::from_raw_parts(
                     self.as_leaf().keys.as_ptr(),
                     self.len()
-                ),
-                slice::from_raw_parts(
-                    self.as_leaf().vals.as_ptr(),
-                    self.len()
                 )
+            }
+        }
+    }
+
+    fn into_val_slice(self) -> &'a [V] {
+        debug_assert!(!self.is_shared_root());
+        unsafe {
+            slice::from_raw_parts(
+                self.as_leaf().vals.as_ptr(),
+                self.len()
             )
         }
     }
+
+    fn into_slices(self) -> (&'a [K], &'a [V]) {
+        let k = unsafe { ptr::read(&self) };
+        (k.into_key_slice(), self.into_val_slice())
+    }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
@@ -535,20 +599,33 @@ pub fn into_root_mut(self) -> &'a mut Root<K, V> {
         }
     }
 
-    pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
-        unsafe {
-            (
+    fn into_key_slice_mut(mut self) -> &'a mut [K] {
+        if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+            &mut []
+        } else {
+            unsafe {
                 slice::from_raw_parts_mut(
                     &mut self.as_leaf_mut().keys as *mut [K] as *mut K,
                     self.len()
-                ),
-                slice::from_raw_parts_mut(
-                    &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
-                    self.len()
                 )
+            }
+        }
+    }
+
+    fn into_val_slice_mut(mut self) -> &'a mut [V] {
+        debug_assert!(!self.is_shared_root());
+        unsafe {
+            slice::from_raw_parts_mut(
+                &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+                self.len()
             )
         }
     }
+
+    fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
+        let k = unsafe { ptr::read(&self) };
+        (k.into_key_slice_mut(), self.into_val_slice_mut())
+    }
 }
 
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
@@ -556,6 +633,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     pub fn push(&mut self, key: K, val: V) {
         // Necessary for correctness, but this is an internal module
         debug_assert!(self.len() < CAPACITY);
+        debug_assert!(!self.is_shared_root());
 
         let idx = self.len();
 
@@ -571,6 +649,7 @@ pub fn push(&mut self, key: K, val: V) {
     pub fn push_front(&mut self, key: K, val: V) {
         // Necessary for correctness, but this is an internal module
         debug_assert!(self.len() < CAPACITY);
+        debug_assert!(!self.is_shared_root());
 
         unsafe {
             slice_insert(self.keys_mut(), 0, key);
@@ -884,6 +963,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
     fn insert_fit(&mut self, key: K, val: V) -> *mut V {
         // Necessary for correctness, but in a private module
         debug_assert!(self.node.len() < CAPACITY);
+        debug_assert!(!self.node.is_shared_root());
 
         unsafe {
             slice_insert(self.node.keys_mut(), self.idx, key);
@@ -1061,6 +1141,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
     ///   allocated node.
     pub fn split(mut self)
             -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+        debug_assert!(!self.node.is_shared_root());
         unsafe {
             let mut new_node = Box::new(LeafNode::new());
 
@@ -1098,6 +1179,7 @@ pub fn split(mut self)
     /// now adjacent key/value pairs to the left and right of this handle.
     pub fn remove(mut self)
             -> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+        debug_assert!(!self.node.is_shared_root());
         unsafe {
             let k = slice_remove(self.node.keys_mut(), self.idx);
             let v = slice_remove(self.node.vals_mut(), self.idx);
index 4d73d3aa07e66590c0e95ba81e1dccc604f54010..5c6f6b22aae068f23d8759c8043fc0da1e497d0a 100644 (file)
@@ -385,26 +385,7 @@ pub fn double_in_place(&mut self) -> bool {
         }
     }
 
-    /// Ensures that the buffer contains at least enough space to hold
-    /// `used_cap + needed_extra_cap` elements. If it doesn't already,
-    /// will reallocate the minimum possible amount of memory necessary.
-    /// Generally this will be exactly the amount of memory necessary,
-    /// but in principle the allocator is free to give back more than
-    /// we asked for.
-    ///
-    /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
-    /// the requested space. This is not really unsafe, but the unsafe
-    /// code *you* write that relies on the behavior of this function may break.
-    ///
-    /// # Panics
-    ///
-    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
-    ///
-    /// # Aborts
-    ///
-    /// Aborts on OOM
+    /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
     pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
            -> Result<(), CollectionAllocErr> {
 
@@ -441,6 +422,26 @@ pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
         }
     }
 
+    /// Ensures that the buffer contains at least enough space to hold
+    /// `used_cap + needed_extra_cap` elements. If it doesn't already,
+    /// will reallocate the minimum possible amount of memory necessary.
+    /// Generally this will be exactly the amount of memory necessary,
+    /// but in principle the allocator is free to give back more than
+    /// we asked for.
+    ///
+    /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
+    /// the requested space. This is not really unsafe, but the unsafe
+    /// code *you* write that relies on the behavior of this function may break.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
+    /// * Panics on 32-bit platforms if the requested capacity exceeds
+    ///   `isize::MAX` bytes.
+    ///
+    /// # Aborts
+    ///
+    /// Aborts on OOM
     pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
         match self.try_reserve_exact(used_cap, needed_extra_cap) {
             Err(CapacityOverflow) => capacity_overflow(),
@@ -463,6 +464,42 @@ fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize)
         Ok(cmp::max(double_cap, required_cap))
     }
 
+    /// The same as `reserve`, but returns on errors instead of panicking or aborting.
+    pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
+        -> Result<(), CollectionAllocErr> {
+         unsafe {
+            // NOTE: we don't early branch on ZSTs here because we want this
+            // to actually catch "asking for more than usize::MAX" in that case.
+            // If we make it past the first branch then we are guaranteed to
+            // panic.
+
+            // Don't actually need any more capacity.
+            // Wrapping in case they give a bad `used_cap`
+            if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
+               return Ok(());
+            }
+
+            let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
+            let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
+
+             // FIXME: may crash and burn on over-reserve
+            alloc_guard(new_layout.size())?;
+
+            let res = match self.current_layout() {
+                Some(layout) => {
+                    debug_assert!(new_layout.align() == layout.align());
+                    self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
+                }
+                None => self.a.alloc(new_layout),
+            };
+
+            self.ptr = res?.cast().into();
+            self.cap = new_cap;
+
+            Ok(())
+        }
+    }
+
     /// Ensures that the buffer contains at least enough space to hold
     /// `used_cap + needed_extra_cap` elements. If it doesn't already have
     /// enough capacity, will reallocate enough space plus comfortable slack
@@ -515,42 +552,6 @@ fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize)
     /// #   vector.push_all(&[1, 3, 5, 7, 9]);
     /// # }
     /// ```
-    pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
-        -> Result<(), CollectionAllocErr> {
-         unsafe {
-            // NOTE: we don't early branch on ZSTs here because we want this
-            // to actually catch "asking for more than usize::MAX" in that case.
-            // If we make it past the first branch then we are guaranteed to
-            // panic.
-
-            // Don't actually need any more capacity.
-            // Wrapping in case they give a bad `used_cap`
-            if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
-               return Ok(());
-            }
-
-            let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
-            let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
-
-             // FIXME: may crash and burn on over-reserve
-            alloc_guard(new_layout.size())?;
-
-            let res = match self.current_layout() {
-                Some(layout) => {
-                    debug_assert!(new_layout.align() == layout.align());
-                    self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
-                }
-                None => self.a.alloc(new_layout),
-            };
-
-            self.ptr = res?.cast().into();
-            self.cap = new_cap;
-
-            Ok(())
-        }
-    }
-
-    /// The same as try_reserve, but errors are lowered to a call to oom().
     pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
         match self.try_reserve(used_cap, needed_extra_cap) {
             Err(CapacityOverflow) => capacity_overflow(),
index d50a3458f20d1cee5043b226801193a4998872ac..6caf12aa7eb81983b9ff6d15c649bf2c7d26edc8 100644 (file)
@@ -10,6 +10,8 @@
 
 //! A dynamically-sized view into a contiguous sequence, `[T]`.
 //!
+//! *[See also the slice primitive type](../../std/primitive.slice.html).*
+//!
 //! Slices are a view into a block of memory represented as a pointer and a
 //! length.
 //!
@@ -78,8 +80,6 @@
 //! * Further methods that return iterators are [`.split`], [`.splitn`],
 //!   [`.chunks`], [`.windows`] and more.
 //!
-//! *[See also the slice primitive type](../../std/primitive.slice.html).*
-//!
 //! [`Clone`]: ../../std/clone/trait.Clone.html
 //! [`Eq`]: ../../std/cmp/trait.Eq.html
 //! [`Ord`]: ../../std/cmp/trait.Ord.html
index 9e693c89be90d06662a408250b896225968dda0e..42efdea74b1ab6aa2b912c3e555e2d74d789850a 100644 (file)
@@ -10,6 +10,8 @@
 
 //! Unicode string slices.
 //!
+//! *[See also the `str` primitive type](../../std/primitive.str.html).*
+//!
 //! The `&str` type is one of the two main string types, the other being `String`.
 //! Unlike its `String` counterpart, its contents are borrowed.
 //!
@@ -29,8 +31,6 @@
 //! ```
 //! let hello_world: &'static str = "Hello, world!";
 //! ```
-//!
-//! *[See also the `str` primitive type](../../std/primitive.str.html).*
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index a03b61ec97e51c71210cc43ef10487266f3ca2e0..1a47e5433ea90d97455c7c8cf8a3ddb556dff6b1 100644 (file)
@@ -291,113 +291,379 @@ fn test_replace_pattern() {
     assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
 }
 
-#[test]
-fn test_slice() {
-    assert_eq!("ab", &"abc"[0..2]);
-    assert_eq!("bc", &"abc"[1..3]);
-    assert_eq!("", &"abc"[1..1]);
-    assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]);
+// The current implementation of SliceIndex fails to handle methods
+// orthogonally from range types; therefore, it is worth testing
+// all of the indexing operations on each input.
+mod slice_index {
+    // Test a slicing operation **that should succeed,**
+    // testing it on all of the indexing methods.
+    //
+    // This is not suitable for testing failure on invalid inputs.
+    macro_rules! assert_range_eq {
+        ($s:expr, $range:expr, $expected:expr)
+        => {
+            let mut s: String = $s.to_owned();
+            let mut expected: String = $expected.to_owned();
+            {
+                let s: &str = &s;
+                let expected: &str = &expected;
+
+                assert_eq!(&s[$range], expected, "(in assertion for: index)");
+                assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
+                unsafe {
+                    assert_eq!(
+                        s.get_unchecked($range), expected,
+                        "(in assertion for: get_unchecked)",
+                    );
+                }
+            }
+            {
+                let s: &mut str = &mut s;
+                let expected: &mut str = &mut expected;
+
+                assert_eq!(
+                    &mut s[$range], expected,
+                    "(in assertion for: index_mut)",
+                );
+                assert_eq!(
+                    s.get_mut($range), Some(&mut expected[..]),
+                    "(in assertion for: get_mut)",
+                );
+                unsafe {
+                    assert_eq!(
+                        s.get_unchecked_mut($range), expected,
+                        "(in assertion for: get_unchecked_mut)",
+                    );
+                }
+            }
+        }
+    }
 
-    let data = "ประเทศไทย中华";
-    assert_eq!("ป", &data[0..3]);
-    assert_eq!("ร", &data[3..6]);
-    assert_eq!("", &data[3..3]);
-    assert_eq!("华", &data[30..33]);
+    // Make sure the macro can actually detect bugs,
+    // because if it can't, then what are we even doing here?
+    //
+    // (Be aware this only demonstrates the ability to detect bugs
+    //  in the FIRST method that panics, as the macro is not designed
+    //  to be used in `should_panic`)
+    #[test]
+    #[should_panic(expected = "out of bounds")]
+    fn assert_range_eq_can_fail_by_panic() {
+        assert_range_eq!("abc", 0..5, "abc");
+    }
 
-    fn a_million_letter_x() -> String {
-        let mut i = 0;
-        let mut rs = String::new();
-        while i < 100000 {
-            rs.push_str("华华华华华华华华华华");
-            i += 1;
+    // (Be aware this only demonstrates the ability to detect bugs
+    //  in the FIRST method it calls, as the macro is not designed
+    //  to be used in `should_panic`)
+    #[test]
+    #[should_panic(expected = "==")]
+    fn assert_range_eq_can_fail_by_inequality() {
+        assert_range_eq!("abc", 0..2, "abc");
+    }
+
+    // Generates test cases for bad index operations.
+    //
+    // This generates `should_panic` test cases for Index/IndexMut
+    // and `None` test cases for get/get_mut.
+    macro_rules! panic_cases {
+        ($(
+            in mod $case_name:ident {
+                data: $data:expr;
+
+                // optional:
+                //
+                // a similar input for which DATA[input] succeeds, and the corresponding
+                // output str. This helps validate "critical points" where an input range
+                // straddles the boundary between valid and invalid.
+                // (such as the input `len..len`, which is just barely valid)
+                $(
+                    good: data[$good:expr] == $output:expr;
+                )*
+
+                bad: data[$bad:expr];
+                message: $expect_msg:expr; // must be a literal
+            }
+        )*) => {$(
+            mod $case_name {
+                #[test]
+                fn pass() {
+                    let mut v: String = $data.into();
+
+                    $( assert_range_eq!(v, $good, $output); )*
+
+                    {
+                        let v: &str = &v;
+                        assert_eq!(v.get($bad), None, "(in None assertion for get)");
+                    }
+
+                    {
+                        let v: &mut str = &mut v;
+                        assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
+                    }
+                }
+
+                #[test]
+                #[should_panic(expected = $expect_msg)]
+                fn index_fail() {
+                    let v: String = $data.into();
+                    let v: &str = &v;
+                    let _v = &v[$bad];
+                }
+
+                #[test]
+                #[should_panic(expected = $expect_msg)]
+                fn index_mut_fail() {
+                    let mut v: String = $data.into();
+                    let v: &mut str = &mut v;
+                    let _v = &mut v[$bad];
+                }
+            }
+        )*};
+    }
+
+    #[test]
+    fn simple_ascii() {
+        assert_range_eq!("abc", .., "abc");
+
+        assert_range_eq!("abc", 0..2, "ab");
+        assert_range_eq!("abc", 0..=1, "ab");
+        assert_range_eq!("abc", ..2, "ab");
+        assert_range_eq!("abc", ..=1, "ab");
+
+        assert_range_eq!("abc", 1..3, "bc");
+        assert_range_eq!("abc", 1..=2, "bc");
+        assert_range_eq!("abc", 1..1, "");
+        assert_range_eq!("abc", 1..=0, "");
+    }
+
+    #[test]
+    fn simple_unicode() {
+        // 日本
+        assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
+
+        assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
+        assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
+        assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
+        assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
+
+        assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
+        assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
+        assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
+
+        let data = "ประเทศไทย中华";
+        assert_range_eq!(data, 0..3, "ป");
+        assert_range_eq!(data, 3..6, "ร");
+        assert_range_eq!(data, 3..3, "");
+        assert_range_eq!(data, 30..33, "华");
+
+        /*0: 中
+          3: 华
+          6: V
+          7: i
+          8: ệ
+         11: t
+         12:
+         13: N
+         14: a
+         15: m */
+        let ss = "中华Việt Nam";
+        assert_range_eq!(ss, 3..6, "华");
+        assert_range_eq!(ss, 6..16, "Việt Nam");
+        assert_range_eq!(ss, 6..=15, "Việt Nam");
+        assert_range_eq!(ss, 6.., "Việt Nam");
+
+        assert_range_eq!(ss, 0..3, "中");
+        assert_range_eq!(ss, 3..7, "华V");
+        assert_range_eq!(ss, 3..=6, "华V");
+        assert_range_eq!(ss, 3..3, "");
+        assert_range_eq!(ss, 3..=2, "");
+    }
+
+    #[test]
+    #[cfg(not(target_arch = "asmjs"))] // hits an OOM
+    fn simple_big() {
+        fn a_million_letter_x() -> String {
+            let mut i = 0;
+            let mut rs = String::new();
+            while i < 100000 {
+                rs.push_str("华华华华华华华华华华");
+                i += 1;
+            }
+            rs
         }
-        rs
+        fn half_a_million_letter_x() -> String {
+            let mut i = 0;
+            let mut rs = String::new();
+            while i < 100000 {
+                rs.push_str("华华华华华");
+                i += 1;
+            }
+            rs
+        }
+        let letters = a_million_letter_x();
+        assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
     }
-    fn half_a_million_letter_x() -> String {
-        let mut i = 0;
-        let mut rs = String::new();
-        while i < 100000 {
-            rs.push_str("华华华华华");
-            i += 1;
+
+    #[test]
+    #[should_panic]
+    fn test_slice_fail() {
+        &"中华Việt Nam"[0..2];
+    }
+
+    panic_cases! {
+        in mod rangefrom_len {
+            data: "abcdef";
+            good: data[6..] == "";
+            bad: data[7..];
+            message: "out of bounds";
+        }
+
+        in mod rangeto_len {
+            data: "abcdef";
+            good: data[..6] == "abcdef";
+            bad: data[..7];
+            message: "out of bounds";
+        }
+
+        in mod rangetoinclusive_len {
+            data: "abcdef";
+            good: data[..=5] == "abcdef";
+            bad: data[..=6];
+            message: "out of bounds";
+        }
+
+        in mod range_len_len {
+            data: "abcdef";
+            good: data[6..6] == "";
+            bad: data[7..7];
+            message: "out of bounds";
+        }
+
+        in mod rangeinclusive_len_len {
+            data: "abcdef";
+            good: data[6..=5] == "";
+            bad: data[7..=6];
+            message: "out of bounds";
         }
-        rs
     }
-    let letters = a_million_letter_x();
-    assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]);
-}
 
-#[test]
-fn test_slice_2() {
-    let ss = "中华Việt Nam";
+    panic_cases! {
+        in mod range_neg_width {
+            data: "abcdef";
+            good: data[4..4] == "";
+            bad: data[4..3];
+            message: "begin <= end (4 <= 3)";
+        }
 
-    assert_eq!("华", &ss[3..6]);
-    assert_eq!("Việt Nam", &ss[6..16]);
+        in mod rangeinclusive_neg_width {
+            data: "abcdef";
+            good: data[4..=3] == "";
+            bad: data[4..=2];
+            message: "begin <= end (4 <= 3)";
+        }
+    }
 
-    assert_eq!("ab", &"abc"[0..2]);
-    assert_eq!("bc", &"abc"[1..3]);
-    assert_eq!("", &"abc"[1..1]);
+    mod overflow {
+        panic_cases! {
+            in mod rangeinclusive {
+                data: "hello";
+                // note: using 0 specifically ensures that the result of overflowing is 0..0,
+                //       so that `get` doesn't simply return None for the wrong reason.
+                bad: data[0..=usize::max_value()];
+                message: "maximum usize";
+            }
 
-    assert_eq!("中", &ss[0..3]);
-    assert_eq!("华V", &ss[3..7]);
-    assert_eq!("", &ss[3..3]);
-    /*0: 中
-      3: 华
-      6: V
-      7: i
-      8: ệ
-     11: t
-     12:
-     13: N
-     14: a
-     15: m */
-}
+            in mod rangetoinclusive {
+                data: "hello";
+                bad: data[..=usize::max_value()];
+                message: "maximum usize";
+            }
+        }
+    }
 
-#[test]
-#[should_panic]
-fn test_slice_fail() {
-    &"中华Việt Nam"[0..2];
-}
+    mod boundary {
+        const DATA: &'static str = "abcαβγ";
+
+        const BAD_START: usize = 4;
+        const GOOD_START: usize = 3;
+        const BAD_END: usize = 6;
+        const GOOD_END: usize = 7;
+        const BAD_END_INCL: usize = BAD_END - 1;
+        const GOOD_END_INCL: usize = GOOD_END - 1;
+
+        // it is especially important to test all of the different range types here
+        // because some of the logic may be duplicated as part of micro-optimizations
+        // to dodge unicode boundary checks on half-ranges.
+        panic_cases! {
+            in mod range_1 {
+                data: super::DATA;
+                bad: data[super::BAD_START..super::GOOD_END];
+                message:
+                    "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+            }
 
-#[test]
-#[should_panic]
-fn test_str_slice_rangetoinclusive_max_panics() {
-    &"hello"[..=usize::max_value()];
-}
+            in mod range_2 {
+                data: super::DATA;
+                bad: data[super::GOOD_START..super::BAD_END];
+                message:
+                    "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+            }
 
-#[test]
-#[should_panic]
-fn test_str_slice_rangeinclusive_max_panics() {
-    &"hello"[1..=usize::max_value()];
-}
+            in mod rangefrom {
+                data: super::DATA;
+                bad: data[super::BAD_START..];
+                message:
+                    "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+            }
 
-#[test]
-#[should_panic]
-fn test_str_slicemut_rangetoinclusive_max_panics() {
-    let mut s = "hello".to_owned();
-    let s: &mut str = &mut s;
-    &mut s[..=usize::max_value()];
-}
+            in mod rangeto {
+                data: super::DATA;
+                bad: data[..super::BAD_END];
+                message:
+                    "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+            }
 
-#[test]
-#[should_panic]
-fn test_str_slicemut_rangeinclusive_max_panics() {
-    let mut s = "hello".to_owned();
-    let s: &mut str = &mut s;
-    &mut s[1..=usize::max_value()];
-}
+            in mod rangeinclusive_1 {
+                data: super::DATA;
+                bad: data[super::BAD_START..=super::GOOD_END_INCL];
+                message:
+                    "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+            }
 
-#[test]
-fn test_str_get_maxinclusive() {
-    let mut s = "hello".to_owned();
-    {
-        let s: &str = &s;
-        assert_eq!(s.get(..=usize::max_value()), None);
-        assert_eq!(s.get(1..=usize::max_value()), None);
+            in mod rangeinclusive_2 {
+                data: super::DATA;
+                bad: data[super::GOOD_START..=super::BAD_END_INCL];
+                message:
+                    "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+            }
+
+            in mod rangetoinclusive {
+                data: super::DATA;
+                bad: data[..=super::BAD_END_INCL];
+                message:
+                    "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+            }
+        }
     }
-    {
-        let s: &mut str = &mut s;
-        assert_eq!(s.get(..=usize::max_value()), None);
-        assert_eq!(s.get(1..=usize::max_value()), None);
+
+    const LOREM_PARAGRAPH: &'static str = "\
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
+    sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
+    quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
+    nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
+    tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
+    gravida nec quam.";
+
+    // check the panic includes the prefix of the sliced string
+    #[test]
+    #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
+    fn test_slice_fail_truncated_1() {
+        &LOREM_PARAGRAPH[..1024];
+    }
+    // check the truncation in the panic message
+    #[test]
+    #[should_panic(expected="luctus, im`[...]")]
+    fn test_slice_fail_truncated_2() {
+        &LOREM_PARAGRAPH[..1024];
     }
 }
 
@@ -446,50 +712,6 @@ fn test_is_char_boundary() {
         }
     }
 }
-const LOREM_PARAGRAPH: &'static str = "\
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
-ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
-eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
-sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
-tempus vel, gravida nec quam.";
-
-// check the panic includes the prefix of the sliced string
-#[test]
-#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
-fn test_slice_fail_truncated_1() {
-    &LOREM_PARAGRAPH[..1024];
-}
-// check the truncation in the panic message
-#[test]
-#[should_panic(expected="luctus, im`[...]")]
-fn test_slice_fail_truncated_2() {
-    &LOREM_PARAGRAPH[..1024];
-}
-
-#[test]
-#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
-fn test_slice_fail_boundary_1() {
-    &"abcαβγ"[4..];
-}
-
-#[test]
-#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
-fn test_slice_fail_boundary_2() {
-    &"abcαβγ"[2..6];
-}
-
-#[test]
-fn test_slice_from() {
-    assert_eq!(&"abcd"[0..], "abcd");
-    assert_eq!(&"abcd"[2..], "cd");
-    assert_eq!(&"abcd"[4..], "");
-}
-#[test]
-fn test_slice_to() {
-    assert_eq!(&"abcd"[..0], "");
-    assert_eq!(&"abcd"[..2], "ab");
-    assert_eq!(&"abcd"[..4], "abcd");
-}
 
 #[test]
 fn test_trim_left_matches() {
index 35d0a69a05abe846942a0caad8d47b5bf08a48e6..690cbcb559bbf6099f4e67b0907bebf9e01051c6 100644 (file)
@@ -2533,9 +2533,11 @@ fn drop(&mut self) {
                 // memmove back untouched tail, update to new length
                 let start = source_vec.len();
                 let tail = self.tail_start;
-                let src = source_vec.as_ptr().offset(tail as isize);
-                let dst = source_vec.as_mut_ptr().offset(start as isize);
-                ptr::copy(src, dst, self.tail_len);
+                if tail != start {
+                    let src = source_vec.as_ptr().offset(tail as isize);
+                    let dst = source_vec.as_mut_ptr().offset(start as isize);
+                    ptr::copy(src, dst, self.tail_len);
+                }
                 source_vec.set_len(start + self.tail_len);
             }
         }
index 2a2f6d96c8dc578d2474742f14c9bab0b36b0408..4cfd7101eb549169cdaeda5313f7c39415b9d736 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2a2f6d96c8dc578d2474742f14c9bab0b36b0408
+Subproject commit 4cfd7101eb549169cdaeda5313f7c39415b9d736
index fb0d2d9c882196da3d7189d234ad7a9a992e5c93..7d3e7af1a1884d2703efced9b9a365c04a2451e6 100644 (file)
     /// value is not necessarily valid to be used to actually access memory.
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
-    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
-    /// and destination may *not* overlap.
+    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+    /// and destination must *not* overlap.
     ///
-    /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
+    /// For regions of memory which might overlap, use [`copy`] instead.
+    ///
+    /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`].
+    ///
+    /// [`copy`]: ./fn.copy.html
+    /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy
     ///
     /// # Safety
     ///
-    /// Beyond requiring that the program must be allowed to access both regions
-    /// of memory, it is Undefined Behavior for source and destination to
-    /// overlap. Care must also be taken with the ownership of `src` and
-    /// `dst`. This method semantically moves the values of `src` into `dst`.
-    /// However it does not drop the contents of `dst`, or prevent the contents
-    /// of `src` from being dropped or used.
+    /// Behavior is undefined if any of the following conditions are violated:
+    ///
+    /// * The region of memory which begins at `src` and has a length of
+    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
+    ///
+    /// * The region of memory which begins at `dst` and has a length of
+    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
+    ///   initialized).
+    ///
+    /// * The two regions of memory must *not* overlap.
+    ///
+    /// * `src` must be properly aligned.
+    ///
+    /// * `dst` must be properly aligned.
+    ///
+    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
+    /// region at `dst` can be used or dropped after calling
+    /// `copy_nonoverlapping`.  `copy_nonoverlapping` creates bitwise copies of
+    /// `T`, regardless of whether `T: Copy`, which can result in undefined
+    /// behavior if both copies are used.
+    ///
+    /// [`Copy`]: ../marker/trait.Copy.html
     ///
     /// # Examples
     ///
-    /// A safe swap function:
+    /// Manually implement [`Vec::append`]:
     ///
     /// ```
-    /// use std::mem;
     /// use std::ptr;
     ///
-    /// # #[allow(dead_code)]
-    /// fn swap<T>(x: &mut T, y: &mut T) {
+    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+    ///     let src_len = src.len();
+    ///     let dst_len = dst.len();
+    ///
+    ///     // Ensure that `dst` has enough capacity to hold all of `src`.
+    ///     dst.reserve(src_len);
+    ///
     ///     unsafe {
-    ///         // Give ourselves some scratch space to work with
-    ///         let mut t: T = mem::uninitialized();
+    ///         // The call to offset is always safe because `Vec` will never
+    ///         // allocate more than `isize::MAX` bytes.
+    ///         let dst = dst.as_mut_ptr().offset(dst_len as isize);
+    ///         let src = src.as_ptr();
+    ///
+    ///         // The two regions cannot overlap becuase mutable references do
+    ///         // not alias, and two different vectors cannot own the same
+    ///         // memory.
+    ///         ptr::copy_nonoverlapping(src, dst, src_len);
+    ///     }
     ///
-    ///         // Perform the swap, `&mut` pointers never alias
-    ///         ptr::copy_nonoverlapping(x, &mut t, 1);
-    ///         ptr::copy_nonoverlapping(y, x, 1);
-    ///         ptr::copy_nonoverlapping(&t, y, 1);
+    ///     unsafe {
+    ///         // Truncate `src` without dropping its contents.
+    ///         src.set_len(0);
     ///
-    ///         // 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);
+    ///         // Notify `dst` that it now holds the contents of `src`.
+    ///         dst.set_len(dst_len + src_len);
     ///     }
     /// }
+    ///
+    /// let mut a = vec!['r'];
+    /// let mut b = vec!['u', 's', 't'];
+    ///
+    /// append(&mut a, &mut b);
+    ///
+    /// assert_eq!(a, &['r', 'u', 's', 't']);
+    /// assert!(b.is_empty());
     /// ```
+    ///
+    /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
     /// and destination may overlap.
     ///
-    /// `copy` is semantically equivalent to C's `memmove`.
+    /// If the source and destination will *never* overlap,
+    /// [`copy_nonoverlapping`] can be used instead.
+    ///
+    /// `copy` is semantically equivalent to C's [`memmove`].
+    ///
+    /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
+    /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove
     ///
     /// # Safety
     ///
-    /// Care must be taken with the ownership of `src` and `dst`.
-    /// This method semantically moves the values of `src` into `dst`.
-    /// However it does not drop the contents of `dst`, or prevent the contents of `src`
-    /// from being dropped or used.
+    /// Behavior is undefined if any of the following conditions are violated:
+    ///
+    /// * The region of memory which begins at `src` and has a length of
+    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
+    ///
+    /// * The region of memory which begins at `dst` and has a length of
+    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
+    ///   initialized).
+    ///
+    /// * `src` must be properly aligned.
+    ///
+    /// * `dst` must be properly aligned.
+    ///
+    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
+    /// region at `dst` can be used or dropped after calling `copy`. `copy`
+    /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which
+    /// can result in undefined behavior if both copies are used.
+    ///
+    /// [`Copy`]: ../marker/trait.Copy.html
     ///
     /// # Examples
     ///
     ///     dst
     /// }
     /// ```
-    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
-    /// bytes of memory starting at `dst` to `val`.
+    /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
+    /// `val`.
+    ///
+    /// `write_bytes` is semantically equivalent to C's [`memset`].
+    ///
+    /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset
+    ///
+    /// # Safety
+    ///
+    /// Behavior is undefined if any of the following conditions are violated:
+    ///
+    /// * The region of memory which begins at `dst` and has a length of
+    ///   `count` bytes must be valid.
+    ///
+    /// * `dst` must be properly aligned.
+    ///
+    /// Additionally, the caller must ensure that writing `count` bytes to the
+    /// given region of memory results in a valid value of `T`. Creating an
+    /// invalid value of `T` can result in undefined behavior. An example is
+    /// provided below.
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::ptr;
     ///
     /// }
     /// assert_eq!(vec, [b'a', b'a', 0, 0]);
     /// ```
+    ///
+    /// Creating an invalid value:
+    ///
+    /// ```no_run
+    /// use std::{mem, ptr};
+    ///
+    /// let mut v = Box::new(0i32);
+    ///
+    /// unsafe {
+    ///     // Leaks the previously held value by overwriting the `Box<T>` with
+    ///     // a null pointer.
+    ///     ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
+    /// }
+    ///
+    /// // At this point, using or dropping `v` results in undefined behavior.
+    /// // v = Box::new(0i32); // ERROR
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
index ddbb59989424f11502b5c4b0f17e8f29498c571c..173dfc36f04c5527494cdf0ccbb78ec6e58972dc 100644 (file)
@@ -587,7 +587,7 @@ fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
 /// that information can be useful. For example, if you want to iterate
 /// backwards, a good start is to know where the end is.
 ///
-/// When implementing an `ExactSizeIterator`, You must also implement
+/// When implementing an `ExactSizeIterator`, you must also implement
 /// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must*
 /// return the exact size of the iterator.
 ///
index 672119eba7f9dc814739c2a93b4db903aecc23e4..4a7dc13f0f2ca69e881e3707d819f8d323c41feb 100644 (file)
@@ -11,9 +11,9 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f32` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
 //! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index 220b23a1e6a016fdd0a7ef5cd7165044e56c7811..801de5e87bd10b002c9c1974bfa871fd4ee83dec 100644 (file)
@@ -11,9 +11,9 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f64` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
 //! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index b01a769eda7fd4201e7239003425d93cbb26e937..697e6a3efde284356e5ce023691e2b0de8a3dc29 100644 (file)
@@ -411,6 +411,21 @@ pub fn start(&self) -> &Idx {
     pub fn end(&self) -> &Idx {
         &self.end
     }
+
+    /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(inclusive_range_methods)]
+    ///
+    /// assert_eq!((3..=5).into_inner(), (3, 5));
+    /// ```
+    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[inline]
+    pub fn into_inner(self) -> (Idx, Idx) {
+        (self.start, self.end)
+    }
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
index 5d0b675e8e4c53639b95e6eae1fa7f0305ca0a43..83dfac7a3a2ea4f09b5e25aeb4033acc751c40d9 100644 (file)
@@ -10,7 +10,7 @@
 
 // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
 
-//! Raw, unsafe pointers, `*const T`, and `*mut T`.
+//! Manually manage memory through raw pointers.
 //!
 //! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
 
 
 /// Executes the destructor (if any) of the pointed-to value.
 ///
-/// This has two use cases:
+/// This is semantically equivalent to calling [`ptr::read`] and discarding
+/// the result, but has the following advantages:
 ///
 /// * It is *required* to use `drop_in_place` to drop unsized types like
 ///   trait objects, because they can't be read out onto the stack and
 ///   dropped normally.
 ///
-/// * It is friendlier to the optimizer to do this over `ptr::read` when
+/// * It is friendlier to the optimizer to do this over [`ptr::read`] when
 ///   dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
 ///   as the compiler doesn't need to prove that it's sound to elide the
 ///   copy.
 ///
+/// [`ptr::read`]: ../ptr/fn.read.html
+///
 /// # Safety
 ///
-/// This has all the same safety problems as `ptr::read` with respect to
-/// invalid pointers, types, and double drops.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `to_drop` must point to valid memory.
+///
+/// * `to_drop` must be properly aligned.
+///
+/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
+/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
+/// foo` counts as a use because it will cause the the value to be dropped
+/// again. [`write`] can be used to overwrite data without causing it to be
+/// dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`write`]: ../ptr/fn.write.html
+///
+/// # Examples
+///
+/// Manually remove the last item from a vector:
+///
+/// ```
+/// use std::ptr;
+/// use std::rc::Rc;
+///
+/// let last = Rc::new(1);
+/// let weak = Rc::downgrade(&last);
+///
+/// let mut v = vec![Rc::new(0), last];
+///
+/// unsafe {
+///     // Without a call `drop_in_place`, the last item would never be dropped,
+///     // and the memory it manages would be leaked.
+///     ptr::drop_in_place(&mut v[1]);
+///     v.set_len(1);
+/// }
+///
+/// assert_eq!(v, &[0.into()]);
+///
+/// // Ensure that the last item was dropped.
+/// assert!(weak.upgrade().is_none());
+/// ```
 #[stable(feature = "drop_in_place", since = "1.8.0")]
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
@@ -93,17 +134,25 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
 /// Swaps the values at two mutable locations of the same type, without
 /// deinitializing either.
 ///
-/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which
-/// is otherwise equivalent. If the values do overlap, then the overlapping
-/// region of memory from `x` will be used. This is demonstrated in the
-/// examples section below.
+/// But for the following two exceptions, this function is semantically
+/// equivalent to [`mem::swap`]:
+///
+/// * It operates on raw pointers instead of references. When references are
+///   available, [`mem::swap`] should be preferred.
+///
+/// * The two pointed-to values may overlap. If the values do overlap, then the
+///   overlapping region of memory from `x` will be used. This is demonstrated
+///   in the examples below.
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
 ///
 /// # Safety
 ///
-/// This function copies the memory through the raw pointers passed to it
-/// as arguments.
+/// Behavior is undefined if any of the following conditions are violated:
 ///
-/// Ensure that these pointers are valid before calling `swap`.
+/// * `x` and `y` must point to valid, initialized memory.
+///
+/// * `x` and `y` must be properly aligned.
 ///
 /// # Examples
 ///
@@ -239,13 +288,39 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
     }
 }
 
-/// Replaces the value at `dest` with `src`, returning the old
-/// value, without dropping either.
+/// Replaces the value at `dest` with `src`, returning the old value, without
+/// dropping either.
+///
+/// This function is semantically equivalent to [`mem::replace`] except that it
+/// operates on raw pointers instead of references. When references are
+/// available, [`mem::replace`] should be preferred.
+///
+/// [`mem::replace`]: ../mem/fn.replace.html
 ///
 /// # Safety
 ///
-/// This is only unsafe because it accepts a raw pointer.
-/// Otherwise, this operation is identical to `mem::replace`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dest` must point to valid, initialized memory.
+///
+/// * `dest` must be properly aligned.
+///
+/// # Examples
+///
+/// ```
+/// use std::ptr;
+///
+/// let mut rust = vec!['b', 'u', 's', 't'];
+///
+/// // `mem::replace` would have the same effect without requiring the unsafe
+/// // block.
+/// let b = unsafe {
+///     ptr::replace(&mut rust[0], 'r')
+/// };
+///
+/// assert_eq!(b, 'b');
+/// assert_eq!(rust, &['r', 'u', 's', 't']);
+/// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
@@ -258,14 +333,23 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///
 /// # Safety
 ///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
 ///
-/// The pointer must be aligned; use `read_unaligned` if that is not the case.
+/// * `src` must point to valid, initialized memory.
+///
+/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
+///   case.
+///
+/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
+/// pointed-to value can be used or dropped after calling `read`. `read` creates
+/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result
+/// in undefined behavior if both copies are used. Note that `*src = foo` counts
+/// as a use because it will attempt to drop the value previously at `*src`.
+/// [`write`] can be used to overwrite data without causing it to be dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`read_unaligned`]: ./fn.read_unaligned.html
+/// [`write`]: ./fn.write.html
 ///
 /// # Examples
 ///
@@ -279,6 +363,44 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(a: &mut T, b: &mut T) {
+///     unsafe {
+///         // Create a bitwise copy of the value at `a` in `tmp`.
+///         let tmp = ptr::read(a);
+///
+///         // Exiting at this point (either by explicitly returning or by
+///         // calling a function which panics) would cause the value in `tmp` to
+///         // be dropped while the same value is still referenced by `a`. This
+///         // could trigger undefined behavior if `T` is not `Copy`.
+///
+///         // Create a bitwise copy of the value at `b` in `a`.
+///         // This is safe because mutable references cannot alias.
+///         ptr::copy_nonoverlapping(b, a, 1);
+///
+///         // As above, exiting here could trigger undefined behavior because
+///         // the same value is referenced by `a` and `b`.
+///
+///         // Move `tmp` into `b`.
+///         ptr::write(b, tmp);
+///     }
+/// }
+///
+/// let mut foo = "foo".to_owned();
+/// let mut bar = "bar".to_owned();
+///
+/// swap(&mut foo, &mut bar);
+///
+/// assert_eq!(foo, "bar");
+/// assert_eq!(bar, "foo");
+/// ```
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn read<T>(src: *const T) -> T {
@@ -290,28 +412,62 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// Reads the value from `src` without moving it. This leaves the
 /// memory in `src` unchanged.
 ///
-/// Unlike `read`, the pointer may be unaligned.
+/// Unlike [`read`], `read_unaligned` works with unaligned pointers.
+///
+/// [`read`]: ./fn.read.html
 ///
 /// # Safety
 ///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must point to valid, initialized memory.
+///
+/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
+/// pointed-to value can be used or dropped after calling `read_unaligned`.
+/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T:
+/// Copy`, and this can result in undefined behavior if both copies are used.
+/// Note that `*src = foo` counts as a use because it will attempt to drop the
+/// value previously at `*src`.  [`write_unaligned`] can be used to overwrite
+/// data without causing it to be dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`write_unaligned`]: ./fn.write_unaligned.html
 ///
 /// # Examples
 ///
-/// Basic usage:
+/// Access members of a packed struct by reference:
 ///
 /// ```
-/// let x = 12;
-/// let y = &x as *const i32;
+/// use std::ptr;
 ///
-/// unsafe {
-///     assert_eq!(std::ptr::read_unaligned(y), 12);
+/// #[repr(packed, C)]
+/// #[derive(Default)]
+/// struct Packed {
+///     _padding: u8,
+///     unaligned: u32,
 /// }
+///
+/// let x = Packed {
+///     _padding: 0x00,
+///     unaligned: 0x01020304,
+/// };
+///
+/// let v = unsafe {
+///     // Take a reference to a 32-bit integer which is not aligned.
+///     let unaligned = &x.unaligned;
+///
+///     // Dereferencing normally will emit an unaligned load instruction,
+///     // causing undefined behavior.
+///     // let v = *unaligned; // ERROR
+///
+///     // Instead, use `read_unaligned` to read improperly aligned values.
+///     let v = ptr::read_unaligned(unaligned);
+///
+///     v
+/// };
+///
+/// // Accessing unaligned values directly is safe.
+/// assert!(x.unaligned == v);
 /// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
@@ -326,11 +482,7 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// # Safety
-///
-/// This operation is marked unsafe because it accepts a raw pointer.
-///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// `write` does not drop the contents of `dst`. This is safe, but it could leak
 /// allocations or resources, so care must be taken not to overwrite an object
 /// that should be dropped.
 ///
@@ -338,9 +490,20 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// memory that has previously been [`read`] from.
+///
+/// [`read`]: ./fn.read.html
+///
+/// # Safety
 ///
-/// The pointer must be aligned; use `write_unaligned` if that is not the case.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must point to valid memory.
+///
+/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
+///   case.
+///
+/// [`write_unaligned`]: ./fn.write_unaligned.html
 ///
 /// # Examples
 ///
@@ -356,6 +519,30 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(a: &mut T, b: &mut T) {
+///     unsafe {
+///         let tmp = ptr::read(a);
+///         ptr::copy_nonoverlapping(b, a, 1);
+///         ptr::write(b, tmp);
+///     }
+/// }
+///
+/// let mut foo = "foo".to_owned();
+/// let mut bar = "bar".to_owned();
+///
+/// swap(&mut foo, &mut bar);
+///
+/// assert_eq!(foo, "bar");
+/// assert_eq!(bar, "foo");
+/// ```
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
@@ -365,36 +552,58 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// Unlike `write`, the pointer may be unaligned.
-///
-/// # Safety
+/// Unlike [`write`], the pointer may be unaligned.
 ///
-/// This operation is marked unsafe because it accepts a raw pointer.
-///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
-/// allocations or resources, so care must be taken not to overwrite an object
-/// that should be dropped.
+/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it
+/// could leak allocations or resources, so care must be taken not to overwrite
+/// an object that should be dropped.
 ///
 /// Additionally, it does not drop `src`. Semantically, `src` is moved into the
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// memory that has previously been read with [`read_unaligned`].
+///
+/// [`write`]: ./fn.write.html
+/// [`read_unaligned`]: ./fn.read_unaligned.html
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must point to valid memory.
 ///
 /// # Examples
 ///
-/// Basic usage:
+/// Access fields in a packed struct:
 ///
 /// ```
-/// let mut x = 0;
-/// let y = &mut x as *mut i32;
-/// let z = 12;
+/// use std::{mem, ptr};
+///
+/// #[repr(packed, C)]
+/// #[derive(Default)]
+/// struct Packed {
+///     _padding: u8,
+///     unaligned: u32,
+/// }
+///
+/// let v = 0x01020304;
+/// let mut x: Packed = unsafe { mem::zeroed() };
 ///
 /// unsafe {
-///     std::ptr::write_unaligned(y, z);
-///     assert_eq!(std::ptr::read_unaligned(y), 12);
+///     // Take a reference to a 32-bit integer which is not aligned.
+///     let unaligned = &mut x.unaligned;
+///
+///     // Dereferencing normally will emit an unaligned store instruction,
+///     // causing undefined behavior.
+///     // *unaligned = v; // ERROR
+///
+///     // Instead, use `write_unaligned` to write improperly aligned values.
+///     ptr::write_unaligned(unaligned, v);
 /// }
-/// ```
+///
+/// // Accessing unaligned values directly is safe.
+/// assert!(x.unaligned == v);
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
@@ -411,6 +620,11 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
+/// Memory read with `read_volatile` should almost always be written to using
+/// [`write_volatile`].
+///
+/// [`write_volatile`]: ./fn.write_volatile.html
+///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -427,12 +641,19 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 ///
 /// # Safety
 ///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must point to valid, initialized memory.
+///
+/// * `src` must be properly aligned.
+///
+/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to
+/// object, regardless of whether `T` is [`Copy`]. Using both values can cause
+/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is
+/// almost certainly incorrect.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`read`]: ./fn.read.html
 ///
 /// # Examples
 ///
@@ -459,6 +680,18 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
+/// Memory written with `write_volatile` should almost always be read from using
+/// [`read_volatile`].
+///
+/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
+/// could leak allocations or resources, so care must be taken not to overwrite
+/// an object that should be dropped.
+///
+/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
+/// location pointed to by `dst`.
+///
+/// [`read_volatile`]: ./fn.read_volatile.html
+///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -475,14 +708,11 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// # Safety
 ///
-/// This operation is marked unsafe because it accepts a raw pointer.
+/// Behavior is undefined if any of the following conditions are violated:
 ///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
-/// allocations or resources, so care must be taken not to overwrite an object
-/// that should be dropped.
+/// * `dst` must point to valid memory.
 ///
-/// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// * `dst` must be properly aligned.
 ///
 /// # Examples
 ///
index 83e8a6e4b683a93f59e3fcd8d01b9409e5fee1f6..93ebc23ac0b0e33f45d3e6ed87519a57902be728 100644 (file)
@@ -2262,6 +2262,12 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
     panic!("slice index starts at {} but ends at {}", index, end);
 }
 
+#[inline(never)]
+#[cold]
+fn slice_index_overflow_fail() -> ! {
+    panic!("attempted to index slice up to maximum usize");
+}
+
 /// A helper trait used for indexing operations.
 #[unstable(feature = "slice_get_slice", issue = "35729")]
 #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
@@ -2538,15 +2544,13 @@ unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
 
     #[inline]
     fn index(self, slice: &[T]) -> &[T] {
-        assert!(self.end != usize::max_value(),
-            "attempted to index slice up to maximum usize");
+        if self.end == usize::max_value() { slice_index_overflow_fail(); }
         (self.start..self.end + 1).index(slice)
     }
 
     #[inline]
     fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        assert!(self.end != usize::max_value(),
-            "attempted to index slice up to maximum usize");
+        if self.end == usize::max_value() { slice_index_overflow_fail(); }
         (self.start..self.end + 1).index_mut(slice)
     }
 }
index b39d9feb35b7e3294be2b3c50a14afe7ddf72c39..df7b2f25a86df19820db40788ec3b27f53e4e33a 100644 (file)
@@ -1849,6 +1849,12 @@ fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
         }
     }
 
+    #[inline(never)]
+    #[cold]
+    fn str_index_overflow_fail() -> ! {
+        panic!("attempted to index str up to maximum usize");
+    }
+
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     impl SliceIndex<str> for ops::RangeFull {
         type Output = str;
@@ -2029,19 +2035,13 @@ impl SliceIndex<str> for ops::RangeInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
-            if let Some(end) = self.end.checked_add(1) {
-                (self.start..end).get(slice)
-            } else {
-                None
-            }
+            if self.end == usize::max_value() { None }
+            else { (self.start..self.end+1).get(slice) }
         }
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if let Some(end) = self.end.checked_add(1) {
-                (self.start..end).get_mut(slice)
-            } else {
-                None
-            }
+            if self.end == usize::max_value() { None }
+            else { (self.start..self.end+1).get_mut(slice) }
         }
         #[inline]
         unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
@@ -2053,14 +2053,12 @@ unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
-            assert!(self.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
+            if self.end == usize::max_value() { str_index_overflow_fail(); }
             (self.start..self.end+1).index(slice)
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            assert!(self.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
+            if self.end == usize::max_value() { str_index_overflow_fail(); }
             (self.start..self.end+1).index_mut(slice)
         }
     }
@@ -2072,40 +2070,30 @@ impl SliceIndex<str> for ops::RangeToInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
-            if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
-                Some(unsafe { self.get_unchecked(slice) })
-            } else {
-                None
-            }
+            if self.end == usize::max_value() { None }
+            else { (..self.end+1).get(slice) }
         }
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
-                Some(unsafe { self.get_unchecked_mut(slice) })
-            } else {
-                None
-            }
+            if self.end == usize::max_value() { None }
+            else { (..self.end+1).get_mut(slice) }
         }
         #[inline]
         unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
-            let ptr = slice.as_ptr();
-            super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1))
+            (..self.end+1).get_unchecked(slice)
         }
         #[inline]
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
-            let ptr = slice.as_ptr();
-            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
+            (..self.end+1).get_unchecked_mut(slice)
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
-            assert!(self.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
+            if self.end == usize::max_value() { str_index_overflow_fail(); }
             (..self.end+1).index(slice)
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            assert!(self.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
+            if self.end == usize::max_value() { str_index_overflow_fail(); }
             (..self.end+1).index_mut(slice)
         }
     }
index c81e5e97cbb7acc5c43927e8d2fae22c14fa2969..19b5c86c4740627b90b953dfb4c51801a690f997 100644 (file)
@@ -376,48 +376,224 @@ fn test_windows_zip() {
     assert_eq!(res, [14, 18, 22, 26]);
 }
 
-#[test]
-fn get_range() {
-    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
-    assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..]));
-    assert_eq!(v.get(..2), Some(&[0, 1][..]));
-    assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..]));
-    assert_eq!(v.get(1..4), Some(&[1, 2, 3][..]));
-    assert_eq!(v.get(7..), None);
-    assert_eq!(v.get(7..10), None);
-}
+// The current implementation of SliceIndex fails to handle methods
+// orthogonally from range types; therefore, it is worth testing
+// all of the indexing operations on each input.
+mod slice_index {
+    // This checks all six indexing methods, given an input range that
+    // should succeed. (it is NOT suitable for testing invalid inputs)
+    macro_rules! assert_range_eq {
+        ($arr:expr, $range:expr, $expected:expr)
+        => {
+            let mut arr = $arr;
+            let mut expected = $expected;
+            {
+                let s: &[_] = &arr;
+                let expected: &[_] = &expected;
+
+                assert_eq!(&s[$range], expected, "(in assertion for: index)");
+                assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
+                unsafe {
+                    assert_eq!(
+                        s.get_unchecked($range), expected,
+                        "(in assertion for: get_unchecked)",
+                    );
+                }
+            }
+            {
+                let s: &mut [_] = &mut arr;
+                let expected: &mut [_] = &mut expected;
+
+                assert_eq!(
+                    &mut s[$range], expected,
+                    "(in assertion for: index_mut)",
+                );
+                assert_eq!(
+                    s.get_mut($range), Some(&mut expected[..]),
+                    "(in assertion for: get_mut)",
+                );
+                unsafe {
+                    assert_eq!(
+                        s.get_unchecked_mut($range), expected,
+                        "(in assertion for: get_unchecked_mut)",
+                    );
+                }
+            }
+        }
+    }
 
-#[test]
-fn get_mut_range() {
-    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
-    assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..]));
-    assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..]));
-    assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..]));
-    assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..]));
-    assert_eq!(v.get_mut(7..), None);
-    assert_eq!(v.get_mut(7..10), None);
-}
+    // Make sure the macro can actually detect bugs,
+    // because if it can't, then what are we even doing here?
+    //
+    // (Be aware this only demonstrates the ability to detect bugs
+    //  in the FIRST method that panics, as the macro is not designed
+    //  to be used in `should_panic`)
+    #[test]
+    #[should_panic(expected = "out of range")]
+    fn assert_range_eq_can_fail_by_panic() {
+        assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
+    }
 
-#[test]
-fn get_unchecked_range() {
-    unsafe {
-        let v: &[i32] = &[0, 1, 2, 3, 4, 5];
-        assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]);
-        assert_eq!(v.get_unchecked(..2), &[0, 1][..]);
-        assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]);
-        assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]);
+    // (Be aware this only demonstrates the ability to detect bugs
+    //  in the FIRST method it calls, as the macro is not designed
+    //  to be used in `should_panic`)
+    #[test]
+    #[should_panic(expected = "==")]
+    fn assert_range_eq_can_fail_by_inequality() {
+        assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]);
     }
-}
 
-#[test]
-fn get_unchecked_mut_range() {
-    unsafe {
-        let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
-        assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]);
-        assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]);
-        assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]);
-        assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]);
+    // Test cases for bad index operations.
+    //
+    // This generates `should_panic` test cases for Index/IndexMut
+    // and `None` test cases for get/get_mut.
+    macro_rules! panic_cases {
+        ($(
+            // each test case needs a unique name to namespace the tests
+            in mod $case_name:ident {
+                data: $data:expr;
+
+                // optional:
+                //
+                // one or more similar inputs for which data[input] succeeds,
+                // and the corresponding output as an array.  This helps validate
+                // "critical points" where an input range straddles the boundary
+                // between valid and invalid.
+                // (such as the input `len..len`, which is just barely valid)
+                $(
+                    good: data[$good:expr] == $output:expr;
+                )*
+
+                bad: data[$bad:expr];
+                message: $expect_msg:expr;
+            }
+        )*) => {$(
+            mod $case_name {
+                #[test]
+                fn pass() {
+                    let mut v = $data;
+
+                    $( assert_range_eq!($data, $good, $output); )*
+
+                    {
+                        let v: &[_] = &v;
+                        assert_eq!(v.get($bad), None, "(in None assertion for get)");
+                    }
+
+                    {
+                        let v: &mut [_] = &mut v;
+                        assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
+                    }
+                }
+
+                #[test]
+                #[should_panic(expected = $expect_msg)]
+                fn index_fail() {
+                    let v = $data;
+                    let v: &[_] = &v;
+                    let _v = &v[$bad];
+                }
+
+                #[test]
+                #[should_panic(expected = $expect_msg)]
+                fn index_mut_fail() {
+                    let mut v = $data;
+                    let v: &mut [_] = &mut v;
+                    let _v = &mut v[$bad];
+                }
+            }
+        )*};
     }
+
+    #[test]
+    fn simple() {
+        let v = [0, 1, 2, 3, 4, 5];
+
+        assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]);
+        assert_range_eq!(v, ..2, [0, 1]);
+        assert_range_eq!(v, ..=1, [0, 1]);
+        assert_range_eq!(v, 2.., [2, 3, 4, 5]);
+        assert_range_eq!(v, 1..4, [1, 2, 3]);
+        assert_range_eq!(v, 1..=3, [1, 2, 3]);
+    }
+
+    panic_cases! {
+        in mod rangefrom_len {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[6..] == [];
+            bad: data[7..];
+            message: "but ends at"; // perhaps not ideal
+        }
+
+        in mod rangeto_len {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[..6] == [0, 1, 2, 3, 4, 5];
+            bad: data[..7];
+            message: "out of range";
+        }
+
+        in mod rangetoinclusive_len {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[..=5] == [0, 1, 2, 3, 4, 5];
+            bad: data[..=6];
+            message: "out of range";
+        }
+
+        in mod range_len_len {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[6..6] == [];
+            bad: data[7..7];
+            message: "out of range";
+        }
+
+        in mod rangeinclusive_len_len {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[6..=5] == [];
+            bad: data[7..=6];
+            message: "out of range";
+        }
+    }
+
+    panic_cases! {
+        in mod range_neg_width {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[4..4] == [];
+            bad: data[4..3];
+            message: "but ends at";
+        }
+
+        in mod rangeinclusive_neg_width {
+            data: [0, 1, 2, 3, 4, 5];
+
+            good: data[4..=3] == [];
+            bad: data[4..=2];
+            message: "but ends at";
+        }
+    }
+
+    panic_cases! {
+        in mod rangeinclusive_overflow {
+            data: [0, 1];
+
+            // note: using 0 specifically ensures that the result of overflowing is 0..0,
+            //       so that `get` doesn't simply return None for the wrong reason.
+            bad: data[0 ..= ::std::usize::MAX];
+            message: "maximum usize";
+        }
+
+        in mod rangetoinclusive_overflow {
+            data: [0, 1];
+
+            bad: data[..= ::std::usize::MAX];
+            message: "maximum usize";
+        }
+    } // panic_cases!
 }
 
 #[test]
index 08daafccc5404e523ffa85bf953122d2c2de4cf4..343c9596c538321395d4d90a33b54301c255bedf 100644 (file)
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// All `str` tests live in collectionstests::str
+// All `str` tests live in liballoc/tests
index 042c523f25f25badec26e7737654afeb65de94ee..0f3b95236f069a5432daaf029dcec5d5a61af1f8 100644 (file)
@@ -23,9 +23,43 @@ fn creation() {
 #[test]
 fn secs() {
     assert_eq!(Duration::new(0, 0).as_secs(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
+    assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1);
     assert_eq!(Duration::from_secs(1).as_secs(), 1);
     assert_eq!(Duration::from_millis(999).as_secs(), 0);
     assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+    assert_eq!(Duration::from_micros(999_999).as_secs(), 0);
+    assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
+    assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+}
+
+#[test]
+fn millis() {
+    assert_eq!(Duration::new(0, 0).subsec_millis(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500);
+    assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50);
+    assert_eq!(Duration::from_secs(1).subsec_millis(), 0);
+    assert_eq!(Duration::from_millis(999).subsec_millis(), 999);
+    assert_eq!(Duration::from_millis(1001).subsec_millis(), 1);
+    assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999);
+    assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
+    assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+}
+
+#[test]
+fn micros() {
+    assert_eq!(Duration::new(0, 0).subsec_micros(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000);
+    assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000);
+    assert_eq!(Duration::from_secs(1).subsec_micros(), 0);
+    assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000);
+    assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000);
+    assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999);
+    assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
+    assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
 }
 
 #[test]
@@ -34,8 +68,12 @@ fn nanos() {
     assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
     assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
     assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
-    assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
-    assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+    assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000);
+    assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000);
+    assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000);
+    assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
+    assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
 }
 
 #[test]
index 8e8b1691c657a3bc0edaa12e336332e82f55a3db..c0b2b2a0bc682abf3fbe56df4108fef764b1fcdd 100644 (file)
@@ -203,8 +203,9 @@ pub const fn from_nanos(nanos: u64) -> Duration {
     ///
     /// [`subsec_nanos`]: #method.subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn as_secs(&self) -> u64 { self.secs }
+    pub const fn as_secs(&self) -> u64 { self.secs }
 
     /// Returns the fractional part of this `Duration`, in milliseconds.
     ///
@@ -222,8 +223,9 @@ pub fn as_secs(&self) -> u64 { self.secs }
     /// assert_eq!(duration.subsec_millis(), 432);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+    pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
 
     /// Returns the fractional part of this `Duration`, in microseconds.
     ///
@@ -241,8 +243,9 @@ pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
     /// assert_eq!(duration.subsec_micros(), 234_567);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+    pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
 
     /// Returns the fractional part of this `Duration`, in nanoseconds.
     ///
@@ -260,8 +263,9 @@ pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
     /// assert_eq!(duration.subsec_nanos(), 10_000_000);
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_nanos(&self) -> u32 { self.nanos }
+    pub const fn subsec_nanos(&self) -> u32 { self.nanos }
 
     /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
     /// if overflow occurred.
index c55df9b39b81b64d84b1f1b661ad4901306541d9..610a9a2a39486580743152b98967c55d6061ccba 100644 (file)
 //! A support library for macro authors when defining new macros.
 //!
 //! This library, provided by the standard distribution, provides the types
-//! consumed in the interfaces of procedurally defined macro definitions.
-//! Currently the primary use of this crate is to provide the ability to define
-//! new custom derive modes through `#[proc_macro_derive]`.
+//! consumed in the interfaces of procedurally defined macro definitions such as
+//! function-like macros `#[proc_macro]`, macro attribures `#[proc_macro_attribute]` and
+//! custom derive attributes`#[proc_macro_derive]`.
 //!
-//! Note that this crate is intentionally very bare-bones currently. The main
-//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
-//! implementations, indicating that it can only go to and come from a string.
+//! Note that this crate is intentionally bare-bones currently.
 //! This functionality is intended to be expanded over time as more surface
 //! area for macro authors is stabilized.
 //!
 use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
 use syntax::parse::{self, token};
-use syntax::symbol::Symbol;
+use syntax::symbol::{keywords, Symbol};
 use syntax::tokenstream;
-use syntax::parse::lexer::comments;
+use syntax::parse::lexer::{self, comments};
 use syntax_pos::{FileMap, Pos, SyntaxContext, FileName};
 use syntax_pos::hygiene::Mark;
 
 /// The main type provided by this crate, representing an abstract stream of
-/// tokens.
+/// tokens, or, more specifically, a sequence of token trees.
+/// The type provide interfaces for iterating over those token trees and, conversely,
+/// collecting a number of token trees into one stream.
 ///
-/// This is both the input and output of `#[proc_macro_derive]` definitions.
-/// Currently it's required to be a list of valid Rust items, but this
-/// restriction may be lifted in the future.
+/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
+/// and `#[proc_macro_derive]` definitions.
 ///
 /// The API of this type is intentionally bare-bones, but it'll be expanded over
 /// time!
@@ -74,9 +73,9 @@
 #[derive(Clone)]
 pub struct TokenStream(tokenstream::TokenStream);
 
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl !Send for TokenStream {}
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl !Sync for TokenStream {}
 
 /// Error returned from `TokenStream::from_str`.
@@ -86,13 +85,13 @@ pub struct LexError {
     _inner: (),
 }
 
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl !Send for LexError {}
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl !Sync for LexError {}
 
 impl TokenStream {
-    /// Returns an empty `TokenStream`.
+    /// Returns an empty `TokenStream` containing no token trees.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn empty() -> TokenStream {
         TokenStream(tokenstream::TokenStream::empty())
@@ -105,6 +104,12 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
+/// Attempts to break the string into tokens and parse those tokens into a token stream.
+/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
+/// or characters not existing in the language.
+///
+/// NOTE: Some errors may cause panics instead of returning `LexError`. We reserve the right to
+/// change these errors into `LexError`s later.
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl FromStr for TokenStream {
     type Err = LexError;
@@ -125,6 +130,9 @@ fn from_str(src: &str) -> Result<TokenStream, LexError> {
     }
 }
 
+/// Prints the token stream as a string that is supposed to be losslessly convertible back
+/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters and negative numeric literals.
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl fmt::Display for TokenStream {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -132,6 +140,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+/// Prints token in a form convenient for debugging.
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl fmt::Debug for TokenStream {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -140,6 +149,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+/// Creates a token stream containing a single token tree.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl From<TokenTree> for TokenStream {
     fn from(tree: TokenTree) -> TokenStream {
@@ -147,6 +157,7 @@ fn from(tree: TokenTree) -> TokenStream {
     }
 }
 
+/// Collects a number of token trees into a single stream.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl iter::FromIterator<TokenTree> for TokenStream {
     fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
@@ -154,7 +165,9 @@ fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
     }
 }
 
-#[unstable(feature = "proc_macro", issue = "38356")]
+/// A "flattening" operation on token streams, collects token trees
+/// from multiple token streams into a single stream.
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl iter::FromIterator<TokenStream> for TokenStream {
     fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
         let mut builder = tokenstream::TokenStreamBuilder::new();
@@ -165,7 +178,7 @@ fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
     }
 }
 
-/// Implementation details for the `TokenTree` type, such as iterators.
+/// Public implementation details for the `TokenStream` type, such as iterators.
 #[unstable(feature = "proc_macro", issue = "38356")]
 pub mod token_stream {
     use syntax::tokenstream;
@@ -173,7 +186,9 @@ pub mod token_stream {
 
     use {TokenTree, TokenStream, Delimiter};
 
-    /// An iterator over `TokenTree`s.
+    /// An iterator over `TokenStream`'s `TokenTree`s.
+    /// The iteration is "shallow", e.g. the iterator doesn't recurse into delimited groups,
+    /// and returns whole groups as token trees.
     #[derive(Clone)]
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub struct IntoIter {
@@ -191,6 +206,12 @@ fn next(&mut self) -> Option<TokenTree> {
                     let next = self.cursor.next_as_stream()?;
                     Some(TokenTree::from_internal(next, &mut self.stack))
                 })?;
+                // HACK: The condition "dummy span + group with empty delimiter" represents an AST
+                // fragment approximately converted into a token stream. This may happen, for
+                // example, with inputs to proc macro attributes, including derives. Such "groups"
+                // need to flattened during iteration over stream's token trees.
+                // Eventually this needs to be removed in favor of keeping original token trees
+                // and not doing the roundtrip through AST.
                 if tree.span().0 == DUMMY_SP {
                     if let TokenTree::Group(ref group) = tree {
                         if group.delimiter() == Delimiter::None {
@@ -217,7 +238,7 @@ fn into_iter(self) -> IntoIter {
 
 /// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
 /// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
-/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
+/// the `TokenStream` `[Ident("a"), Punct('+', Alone), Ident("b")]`.
 ///
 /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
 /// To quote `$` itself, use `$$`.
@@ -268,6 +289,9 @@ pub fn def_site() -> Span {
     }
 
     /// The span of the invocation of the current procedural macro.
+    /// Identifiers created with this span will be resolved as if they were written
+    /// directly at the macro call location (call-site hygiene) and other code
+    /// at the macro call site will be able to refer to them as well.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn call_site() -> Span {
         ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
@@ -355,6 +379,7 @@ pub fn eq(&self, other: &Span) -> bool {
     diagnostic_method!(help, Level::Help);
 }
 
+/// Prints a span in a form convenient for debugging.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Debug for Span {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -460,12 +485,12 @@ fn eq(&self, other: &FileName) -> bool {
 #[unstable(feature = "proc_macro", issue = "38356")]
 #[derive(Clone)]
 pub enum TokenTree {
-    /// A delimited tokenstream
+    /// A token stream surrounded by bracket delimiters.
     Group(Group),
-    /// A unicode identifier
-    Term(Term),
-    /// A punctuation character (`+`, `,`, `$`, etc.).
-    Op(Op),
+    /// An identifier.
+    Ident(Ident),
+    /// A single punctuation character (`+`, `,`, `$`, etc.).
+    Punct(Punct),
     /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc.
     Literal(Literal),
 }
@@ -476,14 +501,14 @@ impl !Send for TokenTree {}
 impl !Sync for TokenTree {}
 
 impl TokenTree {
-    /// Returns the span of this token, accessing the `span` method of each of
-    /// the internal tokens.
+    /// Returns the span of this tree, delegating to the `span` method of
+    /// the contained token or a delimited stream.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn span(&self) -> Span {
         match *self {
             TokenTree::Group(ref t) => t.span(),
-            TokenTree::Term(ref t) => t.span(),
-            TokenTree::Op(ref t) => t.span(),
+            TokenTree::Ident(ref t) => t.span(),
+            TokenTree::Punct(ref t) => t.span(),
             TokenTree::Literal(ref t) => t.span(),
         }
     }
@@ -497,13 +522,14 @@ pub fn span(&self) -> Span {
     pub fn set_span(&mut self, span: Span) {
         match *self {
             TokenTree::Group(ref mut t) => t.set_span(span),
-            TokenTree::Term(ref mut t) => t.set_span(span),
-            TokenTree::Op(ref mut t) => t.set_span(span),
+            TokenTree::Ident(ref mut t) => t.set_span(span),
+            TokenTree::Punct(ref mut t) => t.set_span(span),
             TokenTree::Literal(ref mut t) => t.set_span(span),
         }
     }
 }
 
+/// Prints token treee in a form convenient for debugging.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Debug for TokenTree {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -511,8 +537,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // so don't bother with an extra layer of indirection
         match *self {
             TokenTree::Group(ref tt) => tt.fmt(f),
-            TokenTree::Term(ref tt) => tt.fmt(f),
-            TokenTree::Op(ref tt) => tt.fmt(f),
+            TokenTree::Ident(ref tt) => tt.fmt(f),
+            TokenTree::Punct(ref tt) => tt.fmt(f),
             TokenTree::Literal(ref tt) => tt.fmt(f),
         }
     }
@@ -526,16 +552,16 @@ fn from(g: Group) -> TokenTree {
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<Term> for TokenTree {
-    fn from(g: Term) -> TokenTree {
-        TokenTree::Term(g)
+impl From<Ident> for TokenTree {
+    fn from(g: Ident) -> TokenTree {
+        TokenTree::Ident(g)
     }
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<Op> for TokenTree {
-    fn from(g: Op) -> TokenTree {
-        TokenTree::Op(g)
+impl From<Punct> for TokenTree {
+    fn from(g: Punct) -> TokenTree {
+        TokenTree::Punct(g)
     }
 }
 
@@ -546,23 +572,24 @@ fn from(g: Literal) -> TokenTree {
     }
 }
 
+/// Prints the token tree as a string that is supposed to be losslessly convertible back
+/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters and negative numeric literals.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Display for TokenTree {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             TokenTree::Group(ref t) => t.fmt(f),
-            TokenTree::Term(ref t) => t.fmt(f),
-            TokenTree::Op(ref t) => t.fmt(f),
+            TokenTree::Ident(ref t) => t.fmt(f),
+            TokenTree::Punct(ref t) => t.fmt(f),
             TokenTree::Literal(ref t) => t.fmt(f),
         }
     }
 }
 
-/// A delimited token stream
+/// A delimited token stream.
 ///
-/// A `Group` internally contains a `TokenStream` which is delimited by a
-/// `Delimiter`. Groups represent multiple tokens internally and have a `Span`
-/// for the entire stream.
+/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s.
 #[derive(Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
 pub struct Group {
@@ -586,12 +613,16 @@ pub enum Delimiter {
     Brace,
     /// `[ ... ]`
     Bracket,
-    /// An implicit delimiter, e.g. `$var`, where $var is  `...`.
+    /// `Ø ... Ø`
+    /// An implicit delimiter, that may, for example, appear around tokens coming from a
+    /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
+    /// `$var * 3` where `$var` is `1 + 2`.
+    /// Implicit delimiters may not survive roundtrip of a token stream through a string.
     None,
 }
 
 impl Group {
-    /// Creates a new `group` with the given delimiter and token stream.
+    /// Creates a new `Group` with the given delimiter and token stream.
     ///
     /// This constructor will set the span for this group to
     /// `Span::call_site()`. To change the span you can use the `set_span`
@@ -639,6 +670,9 @@ pub fn set_span(&mut self, span: Span) {
     }
 }
 
+/// Prints the group as a string that should be losslessly convertible back
+/// into the same group (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters.
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Display for Group {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -646,145 +680,181 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// An `Op` is an operator like `+` or `-`, and only represents one character.
+/// An `Punct` is an single punctuation character like `+`, `-` or `#`.
 ///
-/// Operators like `+=` are represented as two instance of `Op` with different
+/// Multicharacter operators like `+=` are represented as two instances of `Punct` with different
 /// forms of `Spacing` returned.
 #[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Copy, Clone, Debug)]
-pub struct Op {
-    op: char,
+#[derive(Clone, Debug)]
+pub struct Punct {
+    ch: char,
     spacing: Spacing,
     span: Span,
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl !Send for Op {}
+impl !Send for Punct {}
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl !Sync for Op {}
+impl !Sync for Punct {}
 
-/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
+/// Whether an `Punct` is followed immediately by another `Punct` or
+/// followed by another token or whitespace.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[unstable(feature = "proc_macro", issue = "38356")]
 pub enum Spacing {
-    /// e.g. `+` is `Alone` in `+ =`.
+    /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`.
     Alone,
-    /// e.g. `+` is `Joint` in `+=`.
+    /// E.g. `+` is `Joint` in `+=` or `'#`.
+    /// Additionally, single quote `'` can join with identifiers to form lifetimes `'ident`.
     Joint,
 }
 
-impl Op {
-    /// Creates a new `Op` from the given character and spacing.
+impl Punct {
+    /// Creates a new `Punct` from the given character and spacing.
+    /// The `ch` argument must be a valid punctuation character permitted by the language,
+    /// otherwise the function will panic.
     ///
-    /// The returned `Op` will have the default span of `Span::call_site()`
+    /// The returned `Punct` will have the default span of `Span::call_site()`
     /// which can be further configured with the `set_span` method below.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn new(op: char, spacing: Spacing) -> Op {
-        Op {
-            op: op,
+    pub fn new(ch: char, spacing: Spacing) -> Punct {
+        const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
+                                       '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
+        if !LEGAL_CHARS.contains(&ch) {
+            panic!("unsupported character `{:?}`", ch)
+        }
+        Punct {
+            ch: ch,
             spacing: spacing,
             span: Span::call_site(),
         }
     }
 
-    /// Returns the character this operation represents, for example `'+'`
+    /// Returns the value of this punctuation character as `char`.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn op(&self) -> char {
-        self.op
+    pub fn as_char(&self) -> char {
+        self.ch
     }
 
-    /// Returns the spacing of this operator, indicating whether it's a joint
-    /// operator with more operators coming next in the token stream or an
-    /// `Alone` meaning that the operator has ended.
+    /// Returns the spacing of this punctuation character, indicating whether it's immediately
+    /// followed by another `Punct` in the token stream, so they can potentially be combined into
+    /// a multicharacter operator (`Joint`), or it's followed by some other token or whitespace
+    /// (`Alone`) so the operator has certainly ended.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn spacing(&self) -> Spacing {
         self.spacing
     }
 
-    /// Returns the span for this operator character
+    /// Returns the span for this punctuation character.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn span(&self) -> Span {
         self.span
     }
 
-    /// Configure the span for this operator's character
+    /// Configure the span for this punctuation character.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn set_span(&mut self, span: Span) {
         self.span = span;
     }
 }
 
+/// Prints the punctuation character as a string that should be losslessly convertible
+/// back into the same character.
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl fmt::Display for Op {
+impl fmt::Display for Punct {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         TokenStream::from(TokenTree::from(self.clone())).fmt(f)
     }
 }
 
-/// An interned string.
-#[derive(Copy, Clone, Debug)]
+/// An identifier (`ident`).
+#[derive(Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub struct Term {
+pub struct Ident {
     sym: Symbol,
     span: Span,
+    is_raw: bool,
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl !Send for Term {}
+impl !Send for Ident {}
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl !Sync for Term {}
+impl !Sync for Ident {}
 
-impl Term {
-    /// Creates a new `Term` with the given `string` as well as the specified
+impl Ident {
+    /// Creates a new `Ident` with the given `string` as well as the specified
     /// `span`.
+    /// The `string` argument must be a valid identifier permitted by the
+    /// language, otherwise the function will panic.
     ///
     /// Note that `span`, currently in rustc, configures the hygiene information
-    /// for this identifier. As of this time `Span::call_site()` explicitly
-    /// opts-in to **non-hygienic** information (aka copy/pasted code) while
-    /// spans like `Span::def_site()` will opt-in to hygienic information,
-    /// meaning that code at the call site of the macro can't access this
-    /// identifier.
+    /// for this identifier.
+    ///
+    /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene
+    /// meaning that identifiers created with this span will be resolved as if they were written
+    /// directly at the location of the macro call, and other code at the macro call site will be
+    /// able to refer to them as well.
+    ///
+    /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene
+    /// meaning that identifiers created with this span will be resolved at the location of the
+    /// macro definition and other code at the macro call site will not be able to refer to them.
     ///
     /// Due to the current importance of hygiene this constructor, unlike other
     /// tokens, requires a `Span` to be specified at construction.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn new(string: &str, span: Span) -> Term {
-        Term {
+    pub fn new(string: &str, span: Span) -> Ident {
+        if !lexer::is_valid_ident(string) {
+            panic!("`{:?}` is not a valid identifier", string)
+        }
+        Ident {
             sym: Symbol::intern(string),
             span,
+            is_raw: false,
         }
     }
 
-    // FIXME: Remove this, do not stabilize
-    /// Get a reference to the interned string.
+    /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn as_str(&self) -> &str {
-        unsafe { &*(&*self.sym.as_str() as *const str) }
+    pub fn new_raw(string: &str, span: Span) -> Ident {
+        let mut ident = Ident::new(string, span);
+        if ident.sym == keywords::Underscore.name() ||
+           token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) {
+            panic!("`{:?}` is not a valid raw identifier", string)
+        }
+        ident.is_raw = true;
+        ident
     }
 
-    /// Returns the span of this `Term`, encompassing the entire string returned
+    /// Returns the span of this `Ident`, encompassing the entire string returned
     /// by `as_str`.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn span(&self) -> Span {
         self.span
     }
 
-    /// Configures the span of this `Term`, possibly changing hygiene
-    /// information.
+    /// Configures the span of this `Ident`, possibly changing its hygiene context.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn set_span(&mut self, span: Span) {
         self.span = span;
     }
 }
 
+/// Prints the identifier as a string that should be losslessly convertible
+/// back into the same identifier.
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl fmt::Display for Term {
+impl fmt::Display for Ident {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.is_raw {
+            f.write_str("r#")?;
+        }
         self.sym.as_str().fmt(f)
     }
 }
 
-/// A literal character (`'a'`), string (`"hello"`), a number (`2.3`), etc.
+/// A literal string (`"hello"`), byte string (`b"hello"`),
+/// character (`'a'`), byte character (`b'a'`), an integer or floating point number
+/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`).
+/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s.
 #[derive(Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
 pub struct Literal {
@@ -805,6 +875,8 @@ macro_rules! suffixed_int_literals {
         /// This function will create an integer like `1u32` where the integer
         /// value specified is the first part of the token and the integral is
         /// also suffixed at the end.
+        /// Literals created from negative numbers may not survive rountrips through
+        /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
         ///
         /// Literals created through this method have the `Span::call_site()`
         /// span by default, which can be configured with the `set_span` method
@@ -829,6 +901,8 @@ macro_rules! unsuffixed_int_literals {
         /// specified on this token, meaning that invocations like
         /// `Literal::i8_unsuffixed(1)` are equivalent to
         /// `Literal::u32_unsuffixed(1)`.
+        /// Literals created from negative numbers may not survive rountrips through
+        /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
         ///
         /// Literals created through this method have the `Span::call_site()`
         /// span by default, which can be configured with the `set_span` method
@@ -880,6 +954,8 @@ impl Literal {
     /// This constructor is similar to those like `Literal::i8_unsuffixed` where
     /// the float's value is emitted directly into the token but no suffix is
     /// used, so it may be inferred to be a `f64` later in the compiler.
+    /// Literals created from negative numbers may not survive rountrips through
+    /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
     ///
     /// # Panics
     ///
@@ -903,6 +979,8 @@ pub fn f32_unsuffixed(n: f32) -> Literal {
     /// specified is the preceding part of the token and `f32` is the suffix of
     /// the token. This token will always be inferred to be an `f32` in the
     /// compiler.
+    /// Literals created from negative numbers may not survive rountrips through
+    /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
     ///
     /// # Panics
     ///
@@ -925,6 +1003,8 @@ pub fn f32_suffixed(n: f32) -> Literal {
     /// This constructor is similar to those like `Literal::i8_unsuffixed` where
     /// the float's value is emitted directly into the token but no suffix is
     /// used, so it may be inferred to be a `f64` later in the compiler.
+    /// Literals created from negative numbers may not survive rountrips through
+    /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
     ///
     /// # Panics
     ///
@@ -948,6 +1028,8 @@ pub fn f64_unsuffixed(n: f64) -> Literal {
     /// specified is the preceding part of the token and `f64` is the suffix of
     /// the token. This token will always be inferred to be an `f64` in the
     /// compiler.
+    /// Literals created from negative numbers may not survive rountrips through
+    /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
     ///
     /// # Panics
     ///
@@ -1016,6 +1098,8 @@ pub fn set_span(&mut self, span: Span) {
     }
 }
 
+/// Prints the literal as a string that should be losslessly convertible
+/// back into the same literal (except for possible rounding for floating point literals).
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Display for Literal {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1068,15 +1152,15 @@ macro_rules! tt {
             })
         }
         macro_rules! op {
-            ($a:expr) => (tt!(Op::new($a, op_kind)));
+            ($a:expr) => (tt!(Punct::new($a, op_kind)));
             ($a:expr, $b:expr) => ({
-                stack.push(tt!(Op::new($b, op_kind)));
-                tt!(Op::new($a, Spacing::Joint))
+                stack.push(tt!(Punct::new($b, op_kind)));
+                tt!(Punct::new($a, Spacing::Joint))
             });
             ($a:expr, $b:expr, $c:expr) => ({
-                stack.push(tt!(Op::new($c, op_kind)));
-                stack.push(tt!(Op::new($b, Spacing::Joint)));
-                tt!(Op::new($a, Spacing::Joint))
+                stack.push(tt!(Punct::new($c, op_kind)));
+                stack.push(tt!(Punct::new($b, Spacing::Joint)));
+                tt!(Punct::new($a, Spacing::Joint))
             })
         }
 
@@ -1127,27 +1211,33 @@ macro_rules! op {
             Pound => op!('#'),
             Dollar => op!('$'),
             Question => op!('?'),
+            SingleQuote => op!('\''),
 
-            Ident(ident, false) | Lifetime(ident) => {
-                tt!(Term::new(&ident.name.as_str(), Span(span)))
+            Ident(ident, false) => {
+                tt!(self::Ident::new(&ident.name.as_str(), Span(span)))
             }
             Ident(ident, true) => {
-                tt!(Term::new(&format!("r#{}", ident), Span(span)))
+                tt!(self::Ident::new_raw(&ident.name.as_str(), Span(span)))
+            }
+            Lifetime(ident) => {
+                let ident = ident.without_first_quote();
+                stack.push(tt!(self::Ident::new(&ident.name.as_str(), Span(span))));
+                tt!(Punct::new('\'', Spacing::Joint))
             }
             Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }),
             DocComment(c) => {
                 let style = comments::doc_comment_style(&c.as_str());
                 let stripped = comments::strip_doc_comment_decoration(&c.as_str());
                 let stream = vec![
-                    tt!(Term::new("doc", Span(span))),
-                    tt!(Op::new('=', Spacing::Alone)),
+                    tt!(self::Ident::new("doc", Span(span))),
+                    tt!(Punct::new('=', Spacing::Alone)),
                     tt!(self::Literal::string(&stripped)),
                 ].into_iter().collect();
                 stack.push(tt!(Group::new(Delimiter::Bracket, stream)));
                 if style == ast::AttrStyle::Inner {
-                    stack.push(tt!(Op::new('!', Spacing::Alone)));
+                    stack.push(tt!(Punct::new('!', Spacing::Alone)));
                 }
-                tt!(Op::new('#', Spacing::Alone))
+                tt!(Punct::new('#', Spacing::Alone))
             }
 
             Interpolated(_) => {
@@ -1167,26 +1257,16 @@ fn to_internal(self) -> tokenstream::TokenStream {
         use syntax::parse::token::*;
         use syntax::tokenstream::{TokenTree, Delimited};
 
-        let (op, kind, span) = match self {
-            self::TokenTree::Op(tt) => (tt.op(), tt.spacing(), tt.span()),
+        let (ch, kind, span) = match self {
+            self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()),
             self::TokenTree::Group(tt) => {
                 return TokenTree::Delimited(tt.span.0, Delimited {
                     delim: tt.delimiter.to_internal(),
                     tts: tt.stream.0.into(),
                 }).into();
             },
-            self::TokenTree::Term(tt) => {
-                let ident = ast::Ident::new(tt.sym, tt.span.0);
-                let sym_str = tt.sym.to_string();
-                let token = if sym_str.starts_with("'") {
-                    Lifetime(ident)
-                } else if sym_str.starts_with("r#") {
-                    let name = Symbol::intern(&sym_str[2..]);
-                    let ident = ast::Ident::new(name, ident.span);
-                    Ident(ident, true)
-                } else {
-                    Ident(ident, false)
-                };
+            self::TokenTree::Ident(tt) => {
+                let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw);
                 return TokenTree::Token(tt.span.0, token).into();
             }
             self::TokenTree::Literal(self::Literal {
@@ -1223,7 +1303,7 @@ fn to_internal(self) -> tokenstream::TokenStream {
             }
         };
 
-        let token = match op {
+        let token = match ch {
             '=' => Eq,
             '<' => Lt,
             '>' => Gt,
@@ -1245,7 +1325,8 @@ fn to_internal(self) -> tokenstream::TokenStream {
             '#' => Pound,
             '$' => Dollar,
             '?' => Question,
-            _ => panic!("unsupported character {}", op),
+            '\'' => SingleQuote,
+            _ => unreachable!(),
         };
 
         let tree = TokenTree::Token(span.0, token);
@@ -1268,7 +1349,7 @@ fn to_internal(self) -> tokenstream::TokenStream {
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
 pub mod __internal {
-    pub use quote::{LiteralKind, Quoter, unquote};
+    pub use quote::{LiteralKind, SpannedSymbol, Quoter, unquote};
 
     use std::cell::Cell;
 
index 70f0b078399817ebf71f40d208e2832e937837a4..390d4bc08682509e9352d442bceec6b7f66db4d8 100644 (file)
 //! This quasiquoter uses macros 2.0 hygiene to reliably access
 //! items from `proc_macro`, to build a `proc_macro::TokenStream`.
 
-use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree};
+use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree};
 
 use syntax::ext::base::{ExtCtxt, ProcMacro};
 use syntax::parse::token;
+use syntax::symbol::Symbol;
 use syntax::tokenstream;
 
 pub struct Quoter;
@@ -35,14 +36,14 @@ macro_rules! tt2ts {
 }
 
 macro_rules! quote_tok {
-    (,) => { tt2ts!(Op::new(',', Spacing::Alone)) };
-    (.) => { tt2ts!(Op::new('.', Spacing::Alone)) };
-    (:) => { tt2ts!(Op::new(':', Spacing::Alone)) };
-    (|) => { tt2ts!(Op::new('|', Spacing::Alone)) };
+    (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) };
+    (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) };
+    (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) };
+    (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) };
     (::) => {
         [
-            TokenTree::from(Op::new(':', Spacing::Joint)),
-            TokenTree::from(Op::new(':', Spacing::Alone)),
+            TokenTree::from(Punct::new(':', Spacing::Joint)),
+            TokenTree::from(Punct::new(':', Spacing::Alone)),
         ].iter()
             .cloned()
             .map(|mut x| {
@@ -51,13 +52,13 @@ macro_rules! quote_tok {
             })
             .collect::<TokenStream>()
     };
-    (!) => { tt2ts!(Op::new('!', Spacing::Alone)) };
-    (<) => { tt2ts!(Op::new('<', Spacing::Alone)) };
-    (>) => { tt2ts!(Op::new('>', Spacing::Alone)) };
-    (_) => { tt2ts!(Op::new('_', Spacing::Alone)) };
+    (!) => { tt2ts!(Punct::new('!', Spacing::Alone)) };
+    (<) => { tt2ts!(Punct::new('<', Spacing::Alone)) };
+    (>) => { tt2ts!(Punct::new('>', Spacing::Alone)) };
+    (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) };
     (0) => { tt2ts!(Literal::i8_unsuffixed(0)) };
-    (&) => { tt2ts!(Op::new('&', Spacing::Alone)) };
-    ($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) };
+    (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) };
+    ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) };
 }
 
 macro_rules! quote_tree {
@@ -110,15 +111,15 @@ fn quote(self) -> TokenStream {
             if after_dollar {
                 after_dollar = false;
                 match tree {
-                    TokenTree::Term(_) => {
+                    TokenTree::Ident(_) => {
                         let tree = TokenStream::from(tree);
                         return Some(quote!(::__internal::unquote(&(unquote tree)),));
                     }
-                    TokenTree::Op(ref tt) if tt.op() == '$' => {}
+                    TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
                     _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
                 }
-            } else if let TokenTree::Op(tt) = tree {
-                if tt.op() == '$' {
+            } else if let TokenTree::Punct(ref tt) = tree {
+                if tt.as_char() == '$' {
                     after_dollar = true;
                     return None;
                 }
@@ -143,9 +144,9 @@ fn quote(self) -> TokenStream {
 impl Quote for TokenTree {
     fn quote(self) -> TokenStream {
         match self {
-            TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )),
+            TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )),
             TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )),
-            TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )),
+            TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )),
             TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )),
         }
     }
@@ -175,15 +176,15 @@ fn quote(self) -> TokenStream {
     }
 }
 
-impl Quote for Op {
+impl Quote for Punct {
     fn quote(self) -> TokenStream {
-        quote!(::Op::new((quote self.op()), (quote self.spacing())))
+        quote!(::Punct::new((quote self.as_char()), (quote self.spacing())))
     }
 }
 
-impl Quote for Term {
+impl Quote for Ident {
     fn quote(self) -> TokenStream {
-        quote!(::Term::new((quote self.sym.as_str()), (quote self.span())))
+        quote!(::Ident::new((quote self.sym.as_str()), (quote self.span())))
     }
 }
 
@@ -195,14 +196,32 @@ fn quote(self) -> TokenStream {
 
 macro_rules! literals {
     ($($i:ident),*; $($raw:ident),*) => {
+        pub struct SpannedSymbol {
+            sym: Symbol,
+            span: Span,
+        }
+
+        impl SpannedSymbol {
+            pub fn new(string: &str, span: Span) -> SpannedSymbol {
+                SpannedSymbol { sym: Symbol::intern(string), span }
+            }
+        }
+
+        impl Quote for SpannedSymbol {
+            fn quote(self) -> TokenStream {
+                quote!(::__internal::SpannedSymbol::new((quote self.sym.as_str()),
+                                                        (quote self.span)))
+            }
+        }
+
         pub enum LiteralKind {
             $($i,)*
             $($raw(u16),)*
         }
 
         impl LiteralKind {
-            pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
-                                            -> Literal {
+            pub fn with_contents_and_suffix(self, contents: SpannedSymbol,
+                                            suffix: Option<SpannedSymbol>) -> Literal {
                 let sym = contents.sym;
                 let suffix = suffix.map(|t| t.sym);
                 match self {
@@ -225,13 +244,14 @@ pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
         }
 
         impl Literal {
-            fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) {
+            fn kind_contents_and_suffix(self) -> (LiteralKind, SpannedSymbol, Option<SpannedSymbol>)
+            {
                 let (kind, contents) = match self.lit {
                     $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)*
                     $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)*
                 };
-                let suffix = self.suffix.map(|sym| Term::new(&sym.as_str(), self.span()));
-                (kind, Term::new(&contents.as_str(), self.span()), suffix)
+                let suffix = self.suffix.map(|sym| SpannedSymbol::new(&sym.as_str(), self.span()));
+                (kind, SpannedSymbol::new(&contents.as_str(), self.span()), suffix)
             }
         }
 
index 118125a19ddef673865af95fe944f6039a2b28d3..d8cf147e3ee4b0b8530e9729e01c8be1a196ed9b 100644 (file)
@@ -582,19 +582,16 @@ fn find_scope_edge(&self,
                   scope_cf_kind: ScopeCfKind) -> (region::Scope, CFGIndex) {
 
         match destination.target_id {
-            hir::ScopeTarget::Block(block_expr_id) => {
+            Ok(loop_id) => {
                 for b in &self.breakable_block_scopes {
-                    if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id {
-                        let scope_id = self.tcx.hir.node_to_hir_id(block_expr_id).local_id;
+                    if b.block_expr_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
+                        let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
                         return (region::Scope::Node(scope_id), match scope_cf_kind {
                             ScopeCfKind::Break => b.break_index,
                             ScopeCfKind::Continue => bug!("can't continue to block"),
                         });
                     }
                 }
-                span_bug!(expr.span, "no block expr for id {}", block_expr_id);
-            }
-            hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => {
                 for l in &self.loop_scopes {
                     if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
                         let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
@@ -604,10 +601,9 @@ fn find_scope_edge(&self,
                         });
                     }
                 }
-                span_bug!(expr.span, "no loop scope for id {}", loop_id);
+                span_bug!(expr.span, "no scope for id {}", loop_id);
             }
-            hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
-                span_bug!(expr.span, "loop scope error: {}",  err),
+            Err(err) => span_bug!(expr.span, "scope error: {}",  err),
         }
     }
 }
index e4f432e7caf494d789bd520299e6774db9cb22bd..4847a7f4ddbec4e6b5f98f9c0e58f6bf44704523 100644 (file)
@@ -60,7 +60,7 @@
 //! user of the `DepNode` API of having to know how to compute the expected
 //! fingerprint for a given set of node parameters.
 
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 use hir::map::DefPathHash;
 use hir::{HirId, ItemLocalId};
@@ -621,13 +621,14 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [input] UsedCrateSource(CrateNum),
     [input] PostorderCnums,
 
-    // This query is not expected to have inputs -- as a result, it's
-    // not a good candidate for "replay" because it's essentially a
-    // pure function of its input (and hence the expectation is that
-    // no caller would be green **apart** from just this
-    // query). Making it anonymous avoids hashing the result, which
+    // These queries are not expected to have inputs -- as a result, they
+    // are not good candidates for "replay" because they are essentially
+    // pure functions of their input (and hence the expectation is that
+    // no caller would be green **apart** from just these
+    // queries). Making them anonymous avoids hashing the result, which
     // may save a bit of time.
     [anon] EraseRegionsTy { ty: Ty<'tcx> },
+    [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
 
     [input] Freevars(DefId),
     [input] MaybeUnusedTraitImport(DefId),
index 22ab1b15c8b8ed225c7a4016a96f335bf80c2dab..797332e699d4b99705cdaf4b9ce446b3cf728f0d 100644 (file)
@@ -12,7 +12,8 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock};
+use rustc_data_structures::small_vec::SmallVec;
+use rustc_data_structures::sync::{Lrc, Lock};
 use std::env;
 use std::hash::Hash;
 use ty::{self, TyCtxt};
@@ -77,10 +78,7 @@ struct DepGraphData {
     /// things available to us. If we find that they are not dirty, we
     /// load the path to the file storing those work-products here into
     /// this map. We can later look for and extract that data.
-    previous_work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
-
-    /// Work-products that we generate in this run.
-    work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
+    previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
     dep_node_debug: Lock<FxHashMap<DepNode, String>>,
 
@@ -90,7 +88,8 @@ struct DepGraphData {
 
 impl DepGraph {
 
-    pub fn new(prev_graph: PreviousDepGraph) -> DepGraph {
+    pub fn new(prev_graph: PreviousDepGraph,
+               prev_work_products: FxHashMap<WorkProductId, WorkProduct>) -> DepGraph {
         // Pre-allocate the fingerprints array. We over-allocate a little so
         // that we hopefully don't have to re-allocate during this compilation
         // session.
@@ -100,8 +99,7 @@ pub fn new(prev_graph: PreviousDepGraph) -> DepGraph {
                                                  (prev_graph_node_count * 115) / 100);
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
-                previous_work_products: RwLock::new(FxHashMap()),
-                work_products: RwLock::new(FxHashMap()),
+                previous_work_products: prev_work_products,
                 dep_node_debug: Lock::new(FxHashMap()),
                 current: Lock::new(CurrentDepGraph::new()),
                 previous: prev_graph,
@@ -131,7 +129,7 @@ pub fn query(&self) -> DepGraphQuery {
         let mut edges = Vec::new();
         for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() {
             let from = current_dep_graph.nodes[index];
-            for &edge_target in edge_targets {
+            for &edge_target in edge_targets.iter() {
                 let to = current_dep_graph.nodes[edge_target];
                 edges.push((from, to));
             }
@@ -209,7 +207,7 @@ pub fn with_task<'gcx, C, A, R>(&self,
         self.with_task_impl(key, cx, arg, false, task,
             |key| OpenTask::Regular(Lock::new(RegularOpenTask {
                 node: key,
-                reads: Vec::new(),
+                reads: SmallVec::new(),
                 read_set: FxHashSet(),
             })),
             |data, key, task| data.borrow_mut().complete_task(key, task))
@@ -230,7 +228,7 @@ fn identity_fn<C, A>(_: C, arg: A) -> A {
 
         self.with_task_impl(key, cx, input, true, identity_fn,
             |_| OpenTask::Ignore,
-            |data, key, _| data.borrow_mut().alloc_node(key, Vec::new()))
+            |data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
     }
 
     fn with_task_impl<'gcx, C, A, R>(
@@ -353,7 +351,7 @@ pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeInde
         if let Some(ref data) = self.data {
             let (result, open_task) = ty::tls::with_context(|icx| {
                 let task = OpenTask::Anon(Lock::new(AnonOpenTask {
-                    reads: Vec::new(),
+                    reads: SmallVec::new(),
                     read_set: FxHashSet(),
                 }));
 
@@ -460,52 +458,20 @@ pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeInd
         self.data.as_ref().unwrap().previous.node_to_index(dep_node)
     }
 
-    /// Indicates that a previous work product exists for `v`. This is
-    /// invoked during initial start-up based on what nodes are clean
-    /// (and what files exist in the incr. directory).
-    pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) {
-        debug!("insert_previous_work_product({:?}, {:?})", v, data);
-        self.data
-            .as_ref()
-            .unwrap()
-            .previous_work_products
-            .borrow_mut()
-            .insert(v.clone(), data);
-    }
-
-    /// Indicates that we created the given work-product in this run
-    /// for `v`. This record will be preserved and loaded in the next
-    /// run.
-    pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) {
-        debug!("insert_work_product({:?}, {:?})", v, data);
-        self.data
-            .as_ref()
-            .unwrap()
-            .work_products
-            .borrow_mut()
-            .insert(v.clone(), data);
-    }
-
     /// Check whether a previous work product exists for `v` and, if
     /// so, return the path that leads to it. Used to skip doing work.
     pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
         self.data
             .as_ref()
             .and_then(|data| {
-                data.previous_work_products.borrow().get(v).cloned()
+                data.previous_work_products.get(v).cloned()
             })
     }
 
-    /// Access the map of work-products created during this run. Only
-    /// used during saving of the dep-graph.
-    pub fn work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
-        self.data.as_ref().unwrap().work_products.borrow()
-    }
-
     /// Access the map of work-products created during the cached run. Only
     /// used during saving of the dep-graph.
-    pub fn previous_work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
-        self.data.as_ref().unwrap().previous_work_products.borrow()
+    pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
+        &self.data.as_ref().unwrap().previous_work_products
     }
 
     #[inline(always)]
@@ -534,15 +500,9 @@ pub fn edge_deduplication_data(&self) -> (u64, u64) {
     }
 
     pub fn serialize(&self) -> SerializedDepGraph {
-        let mut fingerprints = self.fingerprints.borrow_mut();
         let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
 
-        // Make sure we don't run out of bounds below.
-        if current_dep_graph.nodes.len() > fingerprints.len() {
-            fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO);
-        }
-
-        let fingerprints = fingerprints.clone().convert_index_type();
+        let fingerprints = self.fingerprints.borrow().clone().convert_index_type();
         let nodes = current_dep_graph.nodes.clone().convert_index_type();
 
         let total_edge_count: usize = current_dep_graph.edges.iter()
@@ -626,7 +586,7 @@ pub fn try_mark_green<'tcx>(&self,
 
         debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
 
-        let mut current_deps = Vec::new();
+        let mut current_deps = SmallVec::new();
 
         for &dep_dep_node_index in prev_deps {
             let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
@@ -923,7 +883,7 @@ pub enum WorkProductFileKind {
 
 pub(super) struct CurrentDepGraph {
     nodes: IndexVec<DepNodeIndex, DepNode>,
-    edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>,
+    edges: IndexVec<DepNodeIndex, SmallVec<[DepNodeIndex; 8]>>,
     node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
     forbidden_edge: Option<EdgeFilter>,
 
@@ -1061,7 +1021,7 @@ fn complete_eval_always_task(&mut self, key: DepNode, task: OpenTask) -> DepNode
         } = task {
             debug_assert_eq!(node, key);
             let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)];
-            self.alloc_node(node, vec![krate_idx])
+            self.alloc_node(node, SmallVec::one(krate_idx))
         } else {
             bug!("complete_eval_always_task() - Expected eval always task to be popped");
         }
@@ -1107,7 +1067,7 @@ fn read_index(&mut self, source: DepNodeIndex) {
 
     fn alloc_node(&mut self,
                   dep_node: DepNode,
-                  edges: Vec<DepNodeIndex>)
+                  edges: SmallVec<[DepNodeIndex; 8]>)
                   -> DepNodeIndex {
         debug_assert_eq!(self.edges.len(), self.nodes.len());
         debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
@@ -1122,12 +1082,12 @@ fn alloc_node(&mut self,
 
 pub struct RegularOpenTask {
     node: DepNode,
-    reads: Vec<DepNodeIndex>,
+    reads: SmallVec<[DepNodeIndex; 8]>,
     read_set: FxHashSet<DepNodeIndex>,
 }
 
 pub struct AnonOpenTask {
-    reads: Vec<DepNodeIndex>,
+    reads: SmallVec<[DepNodeIndex; 8]>,
     read_set: FxHashSet<DepNodeIndex>,
 }
 
index 3e5dcee113a4ed80e47af327c29306f228b84c95..1fb496cca629ed0210d3f9f851a2e9a3cebeb855 100644 (file)
@@ -1039,10 +1039,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             if let Some(ref label) = destination.label {
                 visitor.visit_label(label);
                 match destination.target_id {
-                    ScopeTarget::Block(node_id) |
-                    ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
-                        visitor.visit_def_mention(Def::Label(node_id)),
-                    ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
+                    Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)),
+                    Err(_) => {},
                 };
             }
             walk_list!(visitor, visit_expr, opt_expr);
@@ -1051,10 +1049,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             if let Some(ref label) = destination.label {
                 visitor.visit_label(label);
                 match destination.target_id {
-                    ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
-                    ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
-                        visitor.visit_def_mention(Def::Label(node_id)),
-                    ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
+                    Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)),
+                    Err(_) => {},
                 };
             }
         }
index 2221ecf07b434913b079643d283b48afeeed7d5f..a62000e10c79f8374116269b5eeb45c534307cea 100644 (file)
@@ -88,3 +88,33 @@ fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
         self.visitor.visit_impl_item(impl_item);
     }
 }
+
+/// A parallel variant of ItemLikeVisitor
+pub trait ParItemLikeVisitor<'hir> {
+    fn visit_item(&self, item: &'hir Item);
+    fn visit_trait_item(&self, trait_item: &'hir TraitItem);
+    fn visit_impl_item(&self, impl_item: &'hir ImplItem);
+}
+
+pub trait IntoVisitor<'hir> {
+    type Visitor: Visitor<'hir>;
+    fn into_visitor(&self) -> Self::Visitor;
+}
+
+pub struct ParDeepVisitor<V>(pub V);
+
+impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
+    where V: IntoVisitor<'hir>
+{
+    fn visit_item(&self, item: &'hir Item) {
+        self.0.into_visitor().visit_item(item);
+    }
+
+    fn visit_trait_item(&self, trait_item: &'hir TraitItem) {
+        self.0.into_visitor().visit_trait_item(trait_item);
+    }
+
+    fn visit_impl_item(&self, impl_item: &'hir ImplItem) {
+        self.0.into_visitor().visit_impl_item(impl_item);
+    }
+}
index 51f0c1d7047c91613c76e3ece8213546ec6db877..7a360f7ee43d483b736c27617195455c3b733c4a 100644 (file)
@@ -928,29 +928,27 @@ fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
     fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
         match destination {
             Some((id, label)) => {
-                let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
-                    hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
+                let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) {
+                    Ok(self.lower_node_id(loop_id).node_id)
                 } else {
-                    hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
+                    Err(hir::LoopIdError::UnresolvedLabel)
                 };
                 hir::Destination {
                     label: self.lower_label(Some(label)),
-                    target_id: hir::ScopeTarget::Loop(target),
+                    target_id,
                 }
             }
             None => {
-                let loop_id = self.loop_scopes
+                let target_id = self.loop_scopes
                     .last()
-                    .map(|innermost_loop_id| *innermost_loop_id);
+                    .map(|innermost_loop_id| *innermost_loop_id)
+                    .map(|id| Ok(self.lower_node_id(id).node_id))
+                    .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
+                    .into();
 
                 hir::Destination {
                     label: None,
-                    target_id: hir::ScopeTarget::Loop(
-                        loop_id
-                            .map(|id| Ok(self.lower_node_id(id).node_id))
-                            .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
-                            .into(),
-                    ),
+                    target_id,
                 }
             }
         }
@@ -1459,10 +1457,9 @@ fn lower_qpath(
                             return n;
                         }
                         assert!(!def_id.is_local());
-                        let n = self.cstore
-                            .item_generics_cloned_untracked(def_id, self.sess)
-                            .regions
-                            .len();
+                        let item_generics =
+                            self.cstore.item_generics_cloned_untracked(def_id, self.sess);
+                        let n = item_generics.own_counts().lifetimes;
                         self.type_def_lifetime_params.insert(def_id, n);
                         n
                     });
@@ -3193,9 +3190,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 let destination = if self.is_in_loop_condition && opt_label.is_none() {
                     hir::Destination {
                         label: None,
-                        target_id: hir::ScopeTarget::Loop(
-                            Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
-                        ),
+                        target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
                     }
                 } else {
                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
@@ -3209,9 +3204,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 hir::ExprAgain(if self.is_in_loop_condition && opt_label.is_none() {
                     hir::Destination {
                         label: None,
-                        target_id: hir::ScopeTarget::Loop(
-                            Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
-                        ),
+                        target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
                     }
                 } else {
                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
@@ -3604,7 +3597,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                             hir::ExprBreak(
                                 hir::Destination {
                                     label: None,
-                                    target_id: hir::ScopeTarget::Block(catch_node),
+                                    target_id: Ok(catch_node),
                                 },
                                 Some(from_err_expr),
                             ),
index 0dc89d64bd50116b02d71039e34e6e32c05eb4d3..3f49e0bfd19837b018ce65970fd9e14de1a59bb2 100644 (file)
@@ -48,6 +48,7 @@
 use ty::maps::Providers;
 
 use rustc_data_structures::indexed_vec;
+use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope};
 
 use serialize::{self, Encoder, Encodable, Decoder, Decodable};
 use std::collections::BTreeMap;
@@ -720,6 +721,31 @@ pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V)
         }
     }
 
+    /// A parallel version of visit_all_item_likes
+    pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V)
+        where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send
+    {
+        scope(|s| {
+            s.spawn(|_| {
+                par_iter(&self.items).for_each(|(_, item)| {
+                    visitor.visit_item(item);
+                });
+            });
+
+            s.spawn(|_| {
+                par_iter(&self.trait_items).for_each(|(_, trait_item)| {
+                    visitor.visit_trait_item(trait_item);
+                });
+            });
+
+            s.spawn(|_| {
+                par_iter(&self.impl_items).for_each(|(_, impl_item)| {
+                    visitor.visit_impl_item(impl_item);
+                });
+            });
+        });
+    }
+
     pub fn body(&self, id: BodyId) -> &Body {
         &self.bodies[&id]
     }
@@ -1476,46 +1502,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-// FIXME(cramertj) this should use `Result` once master compiles w/ a vesion of Rust where
-// `Result` implements `Encodable`/`Decodable`
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum LoopIdResult {
-    Ok(NodeId),
-    Err(LoopIdError),
-}
-impl Into<Result<NodeId, LoopIdError>> for LoopIdResult {
-    fn into(self) -> Result<NodeId, LoopIdError> {
-        match self {
-            LoopIdResult::Ok(ok) => Ok(ok),
-            LoopIdResult::Err(err) => Err(err),
-        }
-    }
-}
-impl From<Result<NodeId, LoopIdError>> for LoopIdResult {
-    fn from(res: Result<NodeId, LoopIdError>) -> Self {
-        match res {
-            Ok(ok) => LoopIdResult::Ok(ok),
-            Err(err) => LoopIdResult::Err(err),
-        }
-    }
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum ScopeTarget {
-    Block(NodeId),
-    Loop(LoopIdResult),
-}
-
-impl ScopeTarget {
-    pub fn opt_id(self) -> Option<NodeId> {
-        match self {
-            ScopeTarget::Block(node_id) |
-            ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => Some(node_id),
-            ScopeTarget::Loop(LoopIdResult::Err(_)) => None,
-        }
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub struct Destination {
     // This is `Some(_)` iff there is an explicit user-specified `label
@@ -1523,7 +1509,7 @@ pub struct Destination {
 
     // These errors are caught and then reported during the diagnostics pass in
     // librustc_passes/loops.rs
-    pub target_id: ScopeTarget,
+    pub target_id: Result<NodeId, LoopIdError>,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
index 1f00a3ab1f5ded464dc5fb701b7725ad9afa0a9e..13fff3aa34274d404dbee5d565e681caa97d4896 100644 (file)
@@ -141,6 +141,15 @@ pub fn simple_name(&self) -> Option<ast::Name> {
         }
     }
 
+    pub fn simple_span(&self) -> Option<Span> {
+        match self.node {
+            PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
+            PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
+                Some(path1.span),
+            _ => None,
+        }
+    }
+
     /// Return variants that are necessary to exist for the pattern to match.
     pub fn necessary_variants(&self) -> Vec<DefId> {
         let mut variants = vec![];
index a7adf28c481b95c3fa352aa6345254df6f6a15be..f56f4e12e7a02b9b16ffa34c2f9119ad0c492235 100644 (file)
@@ -67,7 +67,7 @@ pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result<Fingerprint, Strin
 }
 
 impl ::std::fmt::Display for Fingerprint {
-    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(formatter, "{:x}-{:x}", self.0, self.1)
     }
 }
index 4a001802eacb48c889fa1546418056da900cdea4..6edf1b35bdd734247f59d5c169afdf05d3dedc9e 100644 (file)
@@ -656,22 +656,12 @@ fn hash_stable<W: StableHasherResult>(&self,
 
 impl_stable_hash_for_spanned!(ast::Ident);
 
-impl_stable_hash_for!(enum hir::LoopIdResult {
-    Ok(node_id),
-    Err(loop_id_error)
-});
-
 impl_stable_hash_for!(enum hir::LoopIdError {
     OutsideLoopScope,
     UnlabeledCfInWhileCondition,
     UnresolvedLabel
 });
 
-impl_stable_hash_for!(enum hir::ScopeTarget {
-    Block(node_id),
-    Loop(loop_id_result)
-});
-
 impl<'a> HashStable<StableHashingContext<'a>> for ast::Ident {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
index 1cf9b7bf4780e785a8a2b52a4035201fc7e465ce..f56d701b028794fc629569d6529896db43eab697 100644 (file)
@@ -314,6 +314,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
         token::Token::Pound |
         token::Token::Dollar |
         token::Token::Question |
+        token::Token::SingleQuote |
         token::Token::Whitespace |
         token::Token::Comment |
         token::Token::Eof => {}
index d0d0ab093c87ffbd976c77489d6beebc9a7f89da..31dce2a14c2b783869720488634fb89ed4a7ac5a 100644 (file)
@@ -384,6 +384,30 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::ConstValue<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        use mir::interpret::ConstValue::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            ByVal(val) => {
+                val.hash_stable(hcx, hasher);
+            }
+            ByValPair(a, b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+            ByRef(alloc) => {
+                alloc.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
 impl_stable_hash_for!(enum mir::interpret::Value {
     ByVal(v),
     ByValPair(a, b),
@@ -711,54 +735,40 @@ fn hash_stable<W: StableHasherResult>(&self,
                                           hasher: &mut StableHasher<W>) {
         let ty::Generics {
             parent,
-            parent_regions,
-            parent_types,
-            ref regions,
-            ref types,
+            ref parent_count,
+            ref params,
 
-            // Reverse map to each `TypeParameterDef`'s `index` field, from
+            // Reverse map to each `TypeParamDef`'s `index` field, from
             // `def_id.index` (`def_id.krate` is the same as the item's).
-            type_param_to_index: _, // Don't hash this
+            param_def_id_to_index: _, // Don't hash this
             has_self,
             has_late_bound_regions,
         } = *self;
 
         parent.hash_stable(hcx, hasher);
-        parent_regions.hash_stable(hcx, hasher);
-        parent_types.hash_stable(hcx, hasher);
-        regions.hash_stable(hcx, hasher);
-        types.hash_stable(hcx, hasher);
+        parent_count.hash_stable(hcx, hasher);
+        params.hash_stable(hcx, hasher);
         has_self.hash_stable(hcx, hasher);
         has_late_bound_regions.hash_stable(hcx, hasher);
     }
 }
 
-impl<'a> HashStable<StableHashingContext<'a>>
-for ty::RegionParameterDef {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a>,
-                                          hasher: &mut StableHasher<W>) {
-        let ty::RegionParameterDef {
-            name,
-            def_id,
-            index,
-            pure_wrt_drop
-        } = *self;
-
-        name.hash_stable(hcx, hasher);
-        def_id.hash_stable(hcx, hasher);
-        index.hash_stable(hcx, hasher);
-        pure_wrt_drop.hash_stable(hcx, hasher);
-    }
-}
+impl_stable_hash_for!(enum ty::GenericParamDefKind {
+    Lifetime,
+    Type(ty)
+});
 
-impl_stable_hash_for!(struct ty::TypeParameterDef {
+impl_stable_hash_for!(struct ty::GenericParamDef {
     name,
     def_id,
     index,
+    pure_wrt_drop,
+    kind
+});
+
+impl_stable_hash_for!(struct ty::TypeParamDef {
     has_default,
     object_lifetime_default,
-    pure_wrt_drop,
     synthetic
 });
 
index 725ea9734abf4b2540dee577c378dd90ebe4d334..d681e2e3d34b9b735c634a70c2c420749ff5dbc6 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast;
 use traits::{self, PredicateObligation};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind};
 use ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
 use ty::outlives::Component;
 use ty::subst::{Kind, Substs, UnpackedKind};
@@ -313,12 +313,13 @@ fn constrain_anon_type<FRR: FreeRegionRelations<'tcx>>(
         // `['a]` for the first impl trait and `'b` for the
         // second.
         let mut least_region = None;
-        for region_def in &abstract_type_generics.regions {
-            // Find the index of this region in the list of substitutions.
-            let index = region_def.index as usize;
-
+        for param in &abstract_type_generics.params {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {}
+                _ => continue
+            }
             // Get the value supplied for this region from the substs.
-            let subst_arg = anon_defn.substs.region_at(index);
+            let subst_arg = anon_defn.substs.region_at(param.index as usize);
 
             // Compute the least upper bound of it with the other regions.
             debug!("constrain_anon_types: least_region={:?}", least_region);
@@ -616,10 +617,9 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // during trans.
 
                 let generics = self.tcx.generics_of(def_id);
-                let parent_len = generics.parent_count();
                 let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
                     |(index, &kind)| {
-                        if index < parent_len {
+                        if index < generics.parent_count {
                             // Accommodate missing regions in the parent kinds...
                             self.fold_kind_mapping_missing_regions_to_empty(kind)
                         } else {
index ea3c0a8ddb4507d9c9e3851f6643eab1bc134926..7352c14490d1aaeaaf3f35551447827a80c9e97a 100644 (file)
@@ -14,6 +14,7 @@
 use infer::type_variable::TypeVariableOrigin;
 use ty::{self, Ty, TyInfer, TyVar};
 use syntax_pos::Span;
+use errors::DiagnosticBuilder;
 
 struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
@@ -86,7 +87,11 @@ fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
         }
     }
 
-    pub fn need_type_info(&self, body_id: Option<hir::BodyId>, span: Span, ty: Ty<'tcx>) {
+    pub fn need_type_info_err(&self,
+                            body_id: Option<hir::BodyId>,
+                            span: Span,
+                            ty: Ty<'tcx>)
+                            -> DiagnosticBuilder<'gcx> {
         let ty = self.resolve_type_vars_if_possible(&ty);
         let name = self.extract_type_name(&ty);
 
@@ -142,6 +147,6 @@ pub fn need_type_info(&self, body_id: Option<hir::BodyId>, span: Span, ty: Ty<'t
             err.span_label(target_span, label_message);
         }
 
-        err.emit();
+        err
     }
 }
index c62e7f8d9b6350a8a20350625a08c0b9f8039909..1cc65dcfd1027003ae9258d07fe993d21e0c32e8 100644 (file)
@@ -21,9 +21,9 @@
 use middle::free_region::RegionRelations;
 use middle::region;
 use middle::lang_items;
-use ty::subst::Substs;
+use ty::subst::{Kind, Substs};
 use ty::{TyVid, IntVid, FloatVid};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::TypeFoldable;
 use ty::relate::RelateResult;
@@ -905,34 +905,35 @@ pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin)
         self.next_region_var(RegionVariableOrigin::NLL(origin))
     }
 
-    /// Create a region inference variable for the given
-    /// region parameter definition.
-    pub fn region_var_for_def(&self,
-                              span: Span,
-                              def: &ty::RegionParameterDef)
-                              -> ty::Region<'tcx> {
-        self.next_region_var(EarlyBoundRegion(span, def.name))
-    }
-
-    /// Create a type inference variable for the given
-    /// type parameter definition. The substitutions are
-    /// for actual parameters that may be referred to by
-    /// the default of this type parameter, if it exists.
-    /// E.g. `struct Foo<A, B, C = (A, B)>(...);` when
-    /// used in a path such as `Foo::<T, U>::new()` will
-    /// use an inference variable for `C` with `[T, U]`
-    /// as the substitutions for the default, `(T, U)`.
-    pub fn type_var_for_def(&self,
-                            span: Span,
-                            def: &ty::TypeParameterDef)
-                            -> Ty<'tcx> {
-        let ty_var_id = self.type_variables
-                            .borrow_mut()
-                            .new_var(self.universe(),
-                                     false,
-                                     TypeVariableOrigin::TypeParameterDefinition(span, def.name));
-
-        self.tcx.mk_var(ty_var_id)
+    pub fn var_for_def(&self,
+                       span: Span,
+                       param: &ty::GenericParamDef)
+                       -> Kind<'tcx> {
+        match param.kind {
+            GenericParamDefKind::Lifetime => {
+                // Create a region inference variable for the given
+                // region parameter definition.
+                self.next_region_var(EarlyBoundRegion(span, param.name)).into()
+            }
+            GenericParamDefKind::Type(_) => {
+                // Create a type inference variable for the given
+                // type parameter definition. The substitutions are
+                // for actual parameters that may be referred to by
+                // the default of this type parameter, if it exists.
+                // E.g. `struct Foo<A, B, C = (A, B)>(...);` when
+                // used in a path such as `Foo::<T, U>::new()` will
+                // use an inference variable for `C` with `[T, U]`
+                // as the substitutions for the default, `(T, U)`.
+                let ty_var_id =
+                    self.type_variables
+                        .borrow_mut()
+                        .new_var(self.universe(),
+                                    false,
+                                    TypeVariableOrigin::TypeParameterDefinition(span, param.name));
+
+                self.tcx.mk_var(ty_var_id).into()
+            }
+        }
     }
 
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
@@ -941,10 +942,8 @@ pub fn fresh_substs_for_item(&self,
                                  span: Span,
                                  def_id: DefId)
                                  -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx, def_id, |def, _| {
-            self.region_var_for_def(span, def)
-        }, |def, _| {
-            self.type_var_for_def(span, def)
+        Substs::for_item(self.tcx, def_id, |param, _| {
+            self.var_for_def(span, param)
         })
     }
 
index 879d38c4894435613efa148027289b1f64281672..26ac9d6ee9ea6798f8cd99d63c62250f018ec84a 100644 (file)
@@ -49,8 +49,9 @@
 #![cfg_attr(stage0, feature(dyn_trait))]
 #![feature(from_ref)]
 #![feature(fs_read_write)]
+#![feature(iterator_find_map)]
 #![cfg_attr(windows, feature(libc))]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
 #![feature(macro_vis_matcher)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
index 398d7d5704c7fb4be1f0ca15388f30546efe65d1..4f015ed1ce161c5163c7b1fe8b61306e91f606f9 100644 (file)
 declare_lint! {
     pub SINGLE_USE_LIFETIME,
     Allow,
-   "detects single use lifetimes"
+    "detects lifetime parameters that are only used once"
+}
+
+declare_lint! {
+    pub UNUSED_LIFETIME,
+    Allow,
+    "detects lifetime parameters that are never used"
 }
 
 declare_lint! {
@@ -318,6 +324,7 @@ fn get_lints(&self) -> LintArray {
             UNUSED_UNSAFE,
             UNUSED_MUT,
             SINGLE_USE_LIFETIME,
+            UNUSED_LIFETIME,
             TYVAR_BEHIND_RAW_POINTER,
             ELIDED_LIFETIME_IN_PATH,
             BARE_TRAIT_OBJECT,
index 0ecab50dda22989faeb57d53f0bc642ff068e37d..3a76f75d01833a8dbb9ad6cf0653d2e8fd0c7b10 100644 (file)
@@ -11,7 +11,7 @@
 use hir::def_id::DefId;
 use ty::{self, TyCtxt, layout};
 use ty::subst::Substs;
-use mir::interpret::{Value, PrimVal};
+use mir::interpret::ConstValue;
 use errors::DiagnosticBuilder;
 
 use graphviz::IntoCow;
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
     Unevaluated(DefId, &'tcx Substs<'tcx>),
-    Value(Value),
-}
-
-impl<'tcx> ConstVal<'tcx> {
-    pub fn to_raw_bits(&self) -> Option<u128> {
-        match *self {
-            ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
-                Some(b)
-            },
-            _ => None,
-        }
-    }
-    pub fn unwrap_u64(&self) -> u64 {
-        match self.to_raw_bits() {
-            Some(val) => {
-                assert_eq!(val as u64 as u128, val);
-                val as u64
-            },
-            None => bug!("expected constant u64, got {:#?}", self),
-        }
-    }
+    Value(ConstValue<'tcx>),
 }
 
 #[derive(Clone, Debug)]
index 4400ebc294fd89f4afd114926bb98e17198c6dbf..61c8470b616f833f2284fede138d1002232b44c2 100644 (file)
@@ -38,7 +38,7 @@
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use rustc_target::spec::Target;
-use rustc_data_structures::sync::{MetadataRef, Lrc};
+use rustc_data_structures::sync::{self, MetadataRef, Lrc};
 
 pub use self::NativeLibraryKind::*;
 
@@ -255,6 +255,8 @@ fn encode_metadata<'a, 'tcx>(&self,
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
+pub type CrateStoreDyn = CrateStore + sync::Sync;
+
 // FIXME: find a better place for this?
 pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
     let mut err_count = 0;
index d1a46f5f155637f02624592f1e9d127436a87425..2b1663bed2f40d57844a89bdf7e18c341c234bec 100644 (file)
@@ -453,11 +453,11 @@ fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
             }
         }
 
-        pat.each_binding(|bm, p_id, sp, path1| {
+        pat.each_binding(|bm, p_id, _sp, path1| {
             debug!("adding local variable {} from match with bm {:?}",
                    p_id, bm);
             let name = path1.node;
-            ir.add_live_node_for_node(p_id, VarDefNode(sp));
+            ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
             ir.add_variable(Local(LocalInfo {
                 id: p_id,
                 name: name,
@@ -571,9 +571,6 @@ struct Liveness<'a, 'tcx: 'a> {
     // it probably doesn't now)
     break_ln: NodeMap<LiveNode>,
     cont_ln: NodeMap<LiveNode>,
-
-    // mappings from node ID to LiveNode for "breakable" blocks-- currently only `catch {...}`
-    breakable_block_ln: NodeMap<LiveNode>,
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
@@ -601,7 +598,6 @@ fn new(ir: &'a mut IrMaps<'a, 'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
             users: vec![invalid_users(); num_live_nodes * num_vars],
             break_ln: NodeMap(),
             cont_ln: NodeMap(),
-            breakable_block_ln: NodeMap(),
         }
     }
 
@@ -628,10 +624,10 @@ fn variable(&self, node_id: NodeId, span: Span) -> Variable {
     fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
         F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
     {
-        pat.each_binding(|_bm, p_id, sp, _n| {
+        pat.each_binding(|_bm, p_id, sp, n| {
             let ln = self.live_node(p_id, sp);
-            let var = self.variable(p_id, sp);
-            f(self, ln, var, sp, p_id);
+            let var = self.variable(p_id, n.span);
+            f(self, ln, var, n.span, p_id);
         })
     }
 
@@ -870,7 +866,7 @@ fn compute(&mut self, body: &hir::Expr) -> LiveNode {
     fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
                                -> LiveNode {
         if blk.targeted_by_break {
-            self.breakable_block_ln.insert(blk.id, succ);
+            self.break_ln.insert(blk.id, succ);
         }
         let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
         blk.stmts.iter().rev().fold(succ, |succ, stmt| {
@@ -1055,12 +1051,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           hir::ExprBreak(label, ref opt_expr) => {
               // Find which label this break jumps to
               let target = match label.target_id {
-                    hir::ScopeTarget::Block(node_id) =>
-                        self.breakable_block_ln.get(&node_id),
-                    hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) =>
-                        self.break_ln.get(&node_id),
-                    hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
-                        span_bug!(expr.span, "loop scope error: {}", err),
+                    Ok(node_id) => self.break_ln.get(&node_id),
+                    Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
               }.map(|x| *x);
 
               // Now that we know the label we're going to,
@@ -1075,10 +1067,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           hir::ExprAgain(label) => {
               // Find which label this expr continues to
               let sc = match label.target_id {
-                    hir::ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
-                    hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => node_id,
-                    hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
-                        span_bug!(expr.span, "loop scope error: {}", err),
+                    Ok(node_id) => node_id,
+                    Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
               };
 
               // Now that we know the label we're going to,
@@ -1398,7 +1388,8 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
         },
         None => {
             this.pat_bindings(&local.pat, |this, ln, var, sp, id| {
-                this.warn_about_unused(sp, id, ln, var);
+                let span = local.pat.simple_span().unwrap_or(sp);
+                this.warn_about_unused(span, id, ln, var);
             })
         }
     }
@@ -1497,7 +1488,8 @@ fn should_warn(&self, var: Variable) -> Option<String> {
 
     fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
         for arg in &body.arguments {
-            arg.pat.each_binding(|_bm, p_id, sp, path1| {
+            arg.pat.each_binding(|_bm, p_id, _, path1| {
+                let sp = path1.span;
                 let var = self.variable(p_id, sp);
                 // Ignore unused self.
                 let name = path1.node;
@@ -1541,6 +1533,7 @@ fn warn_about_unused(&self,
 
                 let suggest_underscore_msg = format!("consider using `_{}` instead",
                                                      name);
+
                 if is_assigned {
                     self.ir.tcx
                         .lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
index 3875770a5ff5c50298de2c1154e0d2be4d243241..a4c38333da19e8343550ba11ee954756ecb9333a 100644 (file)
@@ -945,7 +945,7 @@ pub fn cat_rvalue_node(&self,
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
+            ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
             _ => promotable,
         };
 
index ceda72dcd7ae0ab51976be10386baf0c636bd5fb..900fbdfdeadb3c58af9193f68128f55125d475d6 100644 (file)
 //! used between functions, and they operate in a purely top-down
 //! way. Therefore we break lifetime name resolution into a separate pass.
 
-use hir::map::Map;
 use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use hir::map::Map;
 use hir::ItemLocalId;
 use hir::LifetimeName;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
 
+use errors::DiagnosticBuilder;
+use rustc::lint;
+use rustc_data_structures::sync::Lrc;
+use session::Session;
 use std::cell::Cell;
 use std::mem::replace;
-use rustc_data_structures::sync::Lrc;
+use std::slice;
 use syntax::ast;
 use syntax::attr;
 use syntax::ptr::P;
 use syntax_pos::Span;
-use errors::DiagnosticBuilder;
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
-use session::Session;
-use std::slice;
-use rustc::lint;
 
-use hir::{self, GenericParamsExt};
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
+use hir::{self, GenericParamsExt};
 
 /// The origin of a named lifetime definition.
 ///
@@ -230,33 +230,34 @@ struct LifetimeContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
-    // Deep breath. Our representation for poly trait refs contains a single
-    // binder and thus we only allow a single level of quantification. However,
-    // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
-    // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
-    // correct when representing these constraints, we should only introduce one
-    // scope. However, we want to support both locations for the quantifier and
-    // during lifetime resolution we want precise information (so we can't
-    // desugar in an earlier phase).
-
-    // SO, if we encounter a quantifier at the outer scope, we set
-    // trait_ref_hack to true (and introduce a scope), and then if we encounter
-    // a quantifier at the inner scope, we error. If trait_ref_hack is false,
-    // then we introduce the scope at the inner quantifier.
-
-    // I'm sorry.
+
+    /// Deep breath. Our representation for poly trait refs contains a single
+    /// binder and thus we only allow a single level of quantification. However,
+    /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+    /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+    /// correct when representing these constraints, we should only introduce one
+    /// scope. However, we want to support both locations for the quantifier and
+    /// during lifetime resolution we want precise information (so we can't
+    /// desugar in an earlier phase).
+    ///
+    /// SO, if we encounter a quantifier at the outer scope, we set
+    /// trait_ref_hack to true (and introduce a scope), and then if we encounter
+    /// a quantifier at the inner scope, we error. If trait_ref_hack is false,
+    /// then we introduce the scope at the inner quantifier.
+    ///
+    /// I'm sorry.
     trait_ref_hack: bool,
 
-    // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
+    /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
     is_in_fn_syntax: bool,
 
-    // List of labels in the function/method currently under analysis.
+    /// List of labels in the function/method currently under analysis.
     labels_in_fn: Vec<(ast::Name, Span)>,
 
-    // Cache for cross-crate per-definition object lifetime defaults.
+    /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
-    lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
+    lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -272,6 +273,11 @@ enum Scope<'a> {
         /// we should use for an early-bound region?
         next_early_index: u32,
 
+        /// Flag is set to true if, in this binder, `'_` would be
+        /// equivalent to a "single-use region". This is true on
+        /// impls, but not other kinds of items.
+        track_lifetime_uses: bool,
+
         /// Whether or not this binder would serve as the parent
         /// binder for abstract types introduced within. For example:
         ///
@@ -432,7 +438,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
             is_in_fn_syntax: false,
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: DefIdMap(),
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: &mut DefIdMap(),
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -497,6 +503,12 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             | hir::ItemTrait(_, _, ref generics, ..)
             | hir::ItemTraitAlias(ref generics, ..)
             | hir::ItemImpl(_, _, _, ref generics, ..) => {
+                // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
+                // This is not true for other kinds of items.x
+                let track_lifetime_uses = match item.node {
+                    hir::ItemImpl(..) => true,
+                    _ => false,
+                };
                 // These kinds of items have only early bound lifetime parameters.
                 let mut index = if let hir::ItemTrait(..) = item.node {
                     1 // Self comes before lifetimes
@@ -512,6 +524,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                     lifetimes,
                     next_early_index,
                     abstract_type_parent: true,
+                    track_lifetime_uses,
                     s: ROOT_SCOPE,
                 };
                 self.with(scope, |old_scope, this| {
@@ -539,7 +552,7 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        debug!("visit_ty: ty={:?}", ty);
+        debug!("visit_ty: id={:?} ty={:?}", ty.id, ty);
         match ty.node {
             hir::TyBareFn(ref c) => {
                 let next_early_index = self.next_early_index();
@@ -552,6 +565,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         .collect(),
                     s: self.scope,
                     next_early_index,
+                    track_lifetime_uses: true,
                     abstract_type_parent: false,
                 };
                 self.with(scope, |old_scope, this| {
@@ -653,8 +667,8 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                 for lt_def in generics.lifetimes() {
                     let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, &lt_def);
                     if let hir::LifetimeName::Underscore = lt_name {
-                        // Pick the elided lifetime "definition" if one exists and use it to make an
-                        // elision scope.
+                        // Pick the elided lifetime "definition" if one exists and use it to make
+                        // an elision scope.
                         elision = Some(region);
                     } else {
                         lifetimes.insert(lt_name, region);
@@ -673,6 +687,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                             lifetimes,
                             next_early_index,
                             s: this.scope,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         this.with(scope, |_old_scope, this| {
@@ -687,6 +702,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         lifetimes,
                         next_early_index,
                         s: self.scope,
+                        track_lifetime_uses: true,
                         abstract_type_parent: false,
                     };
                     self.with(scope, |_old_scope, this| {
@@ -727,6 +743,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -773,6 +790,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -846,6 +864,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
                                 .collect(),
                             s: self.scope,
                             next_early_index,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         let result = self.with(scope, |old_scope, this| {
@@ -912,6 +931,7 @@ fn visit_poly_trait_ref(
                     .collect(),
                 s: self.scope,
                 next_early_index,
+                track_lifetime_uses: true,
                 abstract_type_parent: false,
             };
             self.with(scope, |old_scope, this| {
@@ -1103,10 +1123,7 @@ fn check_if_label_shadows_lifetime(
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     // FIXME (#24278): non-hygienic comparison
                     if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
@@ -1254,33 +1271,70 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F)
         F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext {
-            tcx, ref mut map, ..
-        } = *self;
+            tcx,
+            map,
+            lifetime_uses,
+            ..
+        } = self;
         let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
         let xcrate_object_lifetime_defaults =
             replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
         let mut this = LifetimeContext {
-            tcx,
-            map: *map,
+            tcx: *tcx,
+            map: map,
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
             is_in_fn_syntax: self.is_in_fn_syntax,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: lifetime_uses,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
+        this.check_uses_for_lifetimes_defined_by_scope();
         debug!("exiting scope {:?}", this.scope);
         self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+    }
+
+    fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
+        let defined_by = match self.scope {
+            Scope::Binder { lifetimes, .. } => lifetimes,
+            _ => {
+                debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+                return;
+            }
+        };
 
-        for (def_id, lifetimeuseset) in &this.lifetime_uses {
+        let mut def_ids: Vec<_> = defined_by.values()
+            .flat_map(|region| match region {
+                Region::EarlyBound(_, def_id, _)
+                | Region::LateBound(_, def_id, _)
+                | Region::Free(_, def_id) => Some(*def_id),
+
+                Region::LateBoundAnon(..) | Region::Static => None,
+            })
+            .collect();
+
+        // ensure that we issue lints in a repeatable order
+        def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
+
+        for def_id in def_ids {
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
+                def_id,
+            );
+
+            let lifetimeuseset = self.lifetime_uses.remove(&def_id);
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
+                lifetimeuseset
+            );
             match lifetimeuseset {
-                &LifetimeUseSet::One(_) => {
-                    let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
+                Some(LifetimeUseSet::One(_)) => {
+                    let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     debug!("node id first={:?}", node_id);
-                    if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
+                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
                         let span = hir_lifetime.span;
                         let id = hir_lifetime.id;
                         debug!(
@@ -1288,22 +1342,41 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F)
                             node_id, span, hir_lifetime
                         );
 
-                        this.tcx
+                        self.tcx
                             .struct_span_lint_node(
                                 lint::builtin::SINGLE_USE_LIFETIME,
                                 id,
                                 span,
                                 &format!(
-                                    "lifetime name `{}` only used once",
+                                    "lifetime parameter `{}` only used once",
                                     hir_lifetime.name.name()
                                 ),
                             )
                             .emit();
                     }
                 }
-                _ => {
+                Some(LifetimeUseSet::Many) => {
                     debug!("Not one use lifetime");
                 }
+                None => {
+                    let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
+                        let span = hir_lifetime.span;
+                        let id = hir_lifetime.id;
+
+                        self.tcx
+                            .struct_span_lint_node(
+                                lint::builtin::UNUSED_LIFETIME,
+                                id,
+                                span,
+                                &format!(
+                                    "lifetime parameter `{}` never used",
+                                    hir_lifetime.name.name()
+                                ),
+                            )
+                            .emit();
+                    }
+                }
             }
         }
     }
@@ -1371,6 +1444,7 @@ fn visit_early_late<F>(
             next_early_index,
             s: self.scope,
             abstract_type_parent: true,
+            track_lifetime_uses: false,
         };
         self.with(scope, move |old_scope, this| {
             this.check_lifetime_params(old_scope, &generics.params);
@@ -1436,10 +1510,7 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
                         break Some(def.shifted(late_depth));
@@ -1588,9 +1659,16 @@ fn visit_segment_parameters(
                     .entry(def_id)
                     .or_insert_with(|| {
                         tcx.generics_of(def_id)
-                            .types
+                            .params
                             .iter()
-                            .map(|def| def.object_lifetime_default)
+                            .filter_map(|param| {
+                                match param.kind {
+                                    GenericParamDefKind::Type(ty) => {
+                                        Some(ty.object_lifetime_default)
+                                    }
+                                    GenericParamDefKind::Lifetime => None,
+                                }
+                            })
                             .collect()
                     })
             };
@@ -1630,6 +1708,7 @@ fn visit_fn_like_elision(
         inputs: &'tcx [P<hir::Ty>],
         output: Option<&'tcx P<hir::Ty>>,
     ) {
+        debug!("visit_fn_like_elision: enter");
         let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
         let arg_scope = Scope::Elision {
             elide: arg_elide.clone(),
@@ -1652,6 +1731,8 @@ fn visit_fn_like_elision(
             None => return,
         };
 
+        debug!("visit_fn_like_elision: determine output");
+
         // Figure out if there's a body we can get argument names from,
         // and whether there's a `self` argument (treated specially).
         let mut assoc_item_kind = None;
@@ -1811,11 +1892,14 @@ fn visit_fn_like_elision(
             Elide::Error(arg_lifetimes)
         };
 
+        debug!("visit_fn_like_elision: elide={:?}", elide);
+
         let scope = Scope::Elision {
             elide,
             s: self.scope,
         };
         self.with(scope, |_, this| this.visit_ty(output));
+        debug!("visit_fn_like_elision: exit");
 
         struct GatherLifetimes<'a> {
             map: &'a NamedRegionMap,
@@ -2086,8 +2170,9 @@ fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::Gen
                         );
                         err.emit();
                     }
-                    hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
-                    hir::LifetimeName::Name(_) => {}
+                    hir::LifetimeName::Fresh(_)
+                    | hir::LifetimeName::Implicit
+                    | hir::LifetimeName::Name(_) => {}
                 }
             }
 
@@ -2139,8 +2224,9 @@ fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::Gen
                             ))
                             .emit();
                     }
-                    hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
-                    hir::LifetimeName::Name(_) => {
+                    hir::LifetimeName::Fresh(_)
+                    | hir::LifetimeName::Implicit
+                    | hir::LifetimeName::Name(_) => {
                         self.resolve_lifetime_ref(bound);
                     }
                 }
@@ -2179,10 +2265,7 @@ fn check_lifetime_def_for_shadowing(
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime.name) {
                         let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
@@ -2202,6 +2285,50 @@ fn check_lifetime_def_for_shadowing(
         }
     }
 
+    /// Returns true if, in the current scope, replacing `'_` would be
+    /// equivalent to a single-use lifetime.
+    fn track_lifetime_uses(&self) -> bool {
+        let mut scope = self.scope;
+        loop {
+            match *scope {
+                Scope::Root => break false,
+
+                // Inside of items, it depends on the kind of item.
+                Scope::Binder {
+                    track_lifetime_uses,
+                    ..
+                } => break track_lifetime_uses,
+
+                // Inside a body, `'_` will use an inference variable,
+                // should be fine.
+                Scope::Body { .. } => break true,
+
+                // A lifetime only used in a fn argument could as well
+                // be replaced with `'_`, as that would generate a
+                // fresh name, too.
+                Scope::Elision {
+                    elide: Elide::FreshLateAnon(_),
+                    ..
+                } => break true,
+
+                // In the return type or other such place, `'_` is not
+                // going to make a fresh name, so we cannot
+                // necessarily replace a single-use lifetime with
+                // `'_`.
+                Scope::Elision {
+                    elide: Elide::Exact(_),
+                    ..
+                } => break false,
+                Scope::Elision {
+                    elide: Elide::Error(_),
+                    ..
+                } => break false,
+
+                Scope::ObjectLifetimeDefault { s, .. } => scope = s,
+            }
+        }
+    }
+
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         if lifetime_ref.id == ast::DUMMY_NODE_ID {
             span_bug!(
@@ -2228,11 +2355,31 @@ fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
             | Region::LateBound(_, def_id, _)
             | Region::EarlyBound(_, def_id, _) => {
                 // A lifetime declared by the user.
-                if !self.lifetime_uses.contains_key(&def_id) {
-                    self.lifetime_uses
-                        .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                let def_local_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if def_local_id == lifetime_ref.id {
+                    // This is weird. Because the HIR defines a
+                    // lifetime *definition* as wrapping a Lifetime,
+                    // we wind up invoking this method also for the
+                    // definitions in some cases (notably
+                    // higher-ranked types). This means that a
+                    // lifetime with one use (e.g., `for<'a> fn(&'a
+                    // u32)`) wind up being counted as two uses.  To
+                    // avoid that, we just ignore the lifetime that
+                    // corresponds to the definition.
                 } else {
-                    self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    let track_lifetime_uses = self.track_lifetime_uses();
+                    debug!(
+                        "insert_lifetime: track_lifetime_uses={}",
+                        track_lifetime_uses
+                    );
+                    if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
+                        debug!("insert_lifetime: first use of {:?}", def_id);
+                        self.lifetime_uses
+                            .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                    } else {
+                        debug!("insert_lifetime: many uses of {:?}", def_id);
+                        self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    }
                 }
             }
         }
index 279908d2b675fae372bbb13780bf293d39fc7220..d6a7d5e8472ac086dab3b6dec23b6cc37664f8cd 100644 (file)
@@ -764,7 +764,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                                      "unions with `Drop` implementations are unstable");
                 } else {
                     let param_env = self.tcx.param_env(def_id);
-                    if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() {
+                    if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
                         emit_feature_err(&self.tcx.sess.parse_sess,
                                         "untagged_unions", item.span, GateIssue::Language,
                                         "unions with non-`Copy` fields are unstable");
index 546c7a920d538fd6d12a653ea0c41ccf9f510088..afdd1c167c6dc781b488a0c06d55be60e757952b 100644 (file)
@@ -10,7 +10,7 @@ macro_rules! err {
 
 pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
 
-pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
+pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};
 
 use std::collections::BTreeMap;
 use std::fmt;
@@ -20,8 +20,10 @@ macro_rules! err {
 use ty::layout::{self, Align, HasDataLayout};
 use middle::region;
 use std::iter;
+use std::io;
 use syntax::ast::Mutability;
 use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
+use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
 
 #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Lock {
@@ -235,7 +237,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Allocation {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer
@@ -254,17 +256,69 @@ pub struct Allocation {
 }
 
 impl Allocation {
-    pub fn from_bytes(slice: &[u8]) -> Self {
+    pub fn from_bytes(slice: &[u8], align: Align) -> Self {
         let mut undef_mask = UndefMask::new(0);
         undef_mask.grow(slice.len() as u64, true);
         Self {
             bytes: slice.to_owned(),
             relocations: BTreeMap::new(),
             undef_mask,
-            align: Align::from_bytes(1, 1).unwrap(),
+            align,
             runtime_mutability: Mutability::Immutable,
         }
     }
+
+    pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
+        Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
+    }
+
+    pub fn undef(size: u64, align: Align) -> Self {
+        assert_eq!(size as usize as u64, size);
+        Allocation {
+            bytes: vec![0; size as usize],
+            relocations: BTreeMap::new(),
+            undef_mask: UndefMask::new(size),
+            align,
+            runtime_mutability: Mutability::Immutable,
+        }
+    }
+}
+
+impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Methods to access integers in the target endianness
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn write_target_uint(
+    endianness: layout::Endian,
+    mut target: &mut [u8],
+    data: u128,
+) -> Result<(), io::Error> {
+    let len = target.len();
+    match endianness {
+        layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
+        layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
+    }
+}
+
+pub fn write_target_int(
+    endianness: layout::Endian,
+    mut target: &mut [u8],
+    data: i128,
+) -> Result<(), io::Error> {
+    let len = target.len();
+    match endianness {
+        layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
+        layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
+    }
+}
+
+pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+    match endianness {
+        layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
+        layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 7289d74bfbb1bd653fa529cd7951ff7da8a11bb6..2cd4bf9d18ca55ef3b3aad375bf292561f818f86 100644 (file)
@@ -3,7 +3,69 @@
 use ty::layout::{Align, HasDataLayout};
 use ty;
 
-use super::{EvalResult, MemoryPointer, PointerArithmetic};
+use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
+
+/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
+/// matches Value's optimizations for easy conversions between these two types
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ConstValue<'tcx> {
+    // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
+    ByVal(PrimVal),
+    // Used only for types with layout::abi::ScalarPair
+    ByValPair(PrimVal, PrimVal),
+    // Used only for the remaining cases
+    ByRef(&'tcx Allocation),
+}
+
+impl<'tcx> ConstValue<'tcx> {
+    #[inline]
+    pub fn from_byval_value(val: Value) -> Self {
+        match val {
+            Value::ByRef(..) => bug!(),
+            Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
+            Value::ByVal(val) => ConstValue::ByVal(val),
+        }
+    }
+
+    #[inline]
+    pub fn to_byval_value(&self) -> Option<Value> {
+        match *self {
+            ConstValue::ByRef(..) => None,
+            ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
+            ConstValue::ByVal(val) => Some(Value::ByVal(val)),
+        }
+    }
+
+    #[inline]
+    pub fn from_primval(val: PrimVal) -> Self {
+        ConstValue::ByVal(val)
+    }
+
+    #[inline]
+    pub fn to_primval(&self) -> Option<PrimVal> {
+        match *self {
+            ConstValue::ByRef(..) => None,
+            ConstValue::ByValPair(..) => None,
+            ConstValue::ByVal(val) => Some(val),
+        }
+    }
+
+    #[inline]
+    pub fn to_bits(&self) -> Option<u128> {
+        match self.to_primval() {
+            Some(PrimVal::Bytes(val)) => Some(val),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_ptr(&self) -> Option<MemoryPointer> {
+        match self.to_primval() {
+            Some(PrimVal::Ptr(ptr)) => Some(ptr),
+            _ => None,
+        }
+    }
+}
 
 /// A `Value` represents a single self-contained Rust value.
 ///
index 11e25322f00726b2e2226f7ae09bfed9f81cf96b..eb12444bcb4c92cc7279bd59a22efcdff47add05 100644 (file)
@@ -13,7 +13,6 @@
 //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
 
 use graphviz::IntoCow;
-use middle::const_val::ConstVal;
 use middle::region;
 use rustc_data_structures::sync::{Lrc};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -1549,11 +1548,7 @@ pub fn function_handle<'a>(
             span,
             ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    // ZST function type
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty
-                })
+                value: ty::Const::zero_sized(tcx, ty),
             },
         })
     }
@@ -1881,11 +1876,17 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
 }
 
 /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
-    use middle::const_val::ConstVal::*;
+pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
+    use middle::const_val::ConstVal;
     match const_val.val {
-        Unevaluated(..) => write!(fmt, "{:?}", const_val),
-        Value(val) => print_miri_value(val, const_val.ty, fmt),
+        ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
+        ConstVal::Value(val) => {
+            if let Some(value) = val.to_byval_value() {
+                print_miri_value(value, const_val.ty, fmt)
+            } else {
+                write!(fmt, "{:?}:{}", val, const_val.ty)
+            }
+        },
     }
 }
 
index 6a9ff39c5f56b191163d8e59256b10a020501ade..67dfad50f4435ee0c67890e913c1517f2ddd9ca1 100644 (file)
@@ -69,7 +69,7 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                 PlaceTy::Ty {
                     ty: match ty.sty {
                         ty::TyArray(inner, size) => {
-                            let size = size.val.unwrap_u64();
+                            let size = size.unwrap_usize(tcx);
                             let len = size - (from as u64) - (to as u64);
                             tcx.mk_array(inner, len)
                         }
index 83dac033f940863377bbba0a791903bb51c9cfa4..245663494ddef1f7ae2c3b8f600e109b0b3da3ec 100644 (file)
@@ -95,6 +95,23 @@ pub enum Lto {
     Fat,
 }
 
+#[derive(Clone, PartialEq, Hash)]
+pub enum CrossLangLto {
+    LinkerPlugin(PathBuf),
+    NoLink,
+    Disabled
+}
+
+impl CrossLangLto {
+    pub fn embed_bitcode(&self) -> bool {
+        match *self {
+            CrossLangLto::LinkerPlugin(_) |
+            CrossLangLto::NoLink => true,
+            CrossLangLto::Disabled => false,
+        }
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Hash)]
 pub enum DebugInfoLevel {
     NoDebugInfo,
@@ -412,6 +429,7 @@ pub struct Options {
 
         // Remap source path prefixes in all output (messages, object files, debug, etc)
         remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+
         edition: Edition [TRACKED],
     }
 );
@@ -777,11 +795,15 @@ mod $mod_desc {
             Some("`string` or `string=string`");
         pub const parse_lto: Option<&'static str> =
             Some("one of `thin`, `fat`, or omitted");
+        pub const parse_cross_lang_lto: Option<&'static str> =
+            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
+                  or the path to the linker plugin");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
+        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
+                    CrossLangLto};
         use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
         use std::path::PathBuf;
 
@@ -986,6 +1008,26 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
             true
         }
 
+        fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
+            if v.is_some() {
+                let mut bool_arg = None;
+                if parse_opt_bool(&mut bool_arg, v) {
+                    *slot = if bool_arg.unwrap() {
+                        CrossLangLto::NoLink
+                    } else {
+                        CrossLangLto::Disabled
+                    };
+                    return true
+                }
+            }
+
+            *slot = match v {
+                None |
+                Some("no-link") => CrossLangLto::NoLink,
+                Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
+            };
+            true
+        }
     }
 ) }
 
@@ -1295,7 +1337,7 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
           "make the current crate share its generic instantiations"),
     chalk: bool = (false, parse_bool, [TRACKED],
           "enable the experimental Chalk-based trait solving engine"),
-    cross_lang_lto: bool = (false, parse_bool, [TRACKED],
+    cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
           "generate build artifacts that are compatible with linker-based LTO."),
 }
 
@@ -2327,7 +2369,7 @@ mod dep_tracking {
     use std::path::PathBuf;
     use std::collections::hash_map::DefaultHasher;
     use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
-                Passes, Sanitizer};
+                Passes, Sanitizer, CrossLangLto};
     use syntax::feature_gate::UnstableFeatures;
     use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
     use syntax::edition::Edition;
@@ -2391,6 +2433,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
     impl_dep_tracking_hash_via_hash!(TargetTriple);
     impl_dep_tracking_hash_via_hash!(Edition);
+    impl_dep_tracking_hash_via_hash!(CrossLangLto);
 
     impl_dep_tracking_hash_for_sortable_vec_of!(String);
     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
@@ -2455,7 +2498,7 @@ mod tests {
     use lint;
     use middle::cstore;
     use session::config::{build_configuration, build_session_options_and_crate_config};
-    use session::config::Lto;
+    use session::config::{Lto, CrossLangLto};
     use session::build_session;
     use std::collections::{BTreeMap, BTreeSet};
     use std::iter::FromIterator;
@@ -3111,6 +3154,10 @@ fn test_debugging_options_tracking_hash() {
         opts = reference.clone();
         opts.debugging_opts.relro_level = Some(RelroLevel::Full);
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+        opts = reference.clone();
+        opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
     }
 
     #[test]
index 2ab72ba20bf4fc4b321ed9bd76b144e60efea2ea..bbf873290a928f76a277fb5ef8213fc7b8adb831 100644 (file)
@@ -657,6 +657,13 @@ pub fn crt_static_feature(&self) -> bool {
         }
     }
 
+    pub fn target_cpu(&self) -> &str {
+        match self.opts.cg.target_cpu {
+            Some(ref s) => &**s,
+            None => &*self.target.target.options.cpu
+        }
+    }
+
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         if let Some(x) = self.opts.cg.force_frame_pointers {
             x
@@ -862,10 +869,16 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
         ret
     }
 
+    /// Returns the number of query threads that should be used for this
+    /// compilation
+    pub fn query_threads_from_opts(opts: &config::Options) -> usize {
+        opts.debugging_opts.query_threads.unwrap_or(1)
+    }
+
     /// Returns the number of query threads that should be used for this
     /// compilation
     pub fn query_threads(&self) -> usize {
-        self.opts.debugging_opts.query_threads.unwrap_or(1)
+        Self::query_threads_from_opts(&self.opts)
     }
 
     /// Returns the number of codegen units that should be used for this
index 5d708f60604f1599f268b1a3ff0875df82aac949..227cba40d146388a016431509201bd3a522f3c94 100644 (file)
@@ -222,9 +222,14 @@ pub fn find_auto_trait_generics<A>(
             });
 
             let names_map: FxHashSet<String> = generics
-                .regions
+                .params
                 .iter()
-                .map(|l| l.name.to_string())
+                .filter_map(|param| {
+                    match param.kind {
+                        ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
+                        _ => None
+                    }
+                })
                 .collect();
 
             let body_ids: FxHashSet<_> = infcx
index 25be4a2ff5c8b086633c4d87de95ff94e4fbdeb5..e4520bce68199a5ea233cc1053ffc2a4ead7464b 100644 (file)
@@ -36,6 +36,7 @@
 use syntax::ast;
 use session::DiagnosticMessageId;
 use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use ty::GenericParamDefKind;
 use ty::error::ExpectedFound;
 use ty::fast_reject;
 use ty::fold::TypeFolder;
@@ -378,12 +379,15 @@ fn on_unimplemented_note(
             flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string())));
         }
 
-        for param in generics.types.iter() {
+        for param in generics.params.iter() {
+            let value = match param.kind {
+                GenericParamDefKind::Type(_) => {
+                    trait_ref.substs[param.index as usize].to_string()
+                },
+                GenericParamDefKind::Lifetime => continue,
+            };
             let name = param.name.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())));
+            flags.push((name, Some(value)));
         }
 
         if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) {
@@ -1234,7 +1238,7 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
                         self.tcx.lang_items().sized_trait()
                         .map_or(false, |sized_id| sized_id == trait_ref.def_id())
                     {
-                        self.need_type_info(body_id, span, self_ty);
+                        self.need_type_info_err(body_id, span, self_ty).emit();
                     } else {
                         let mut err = struct_span_err!(self.tcx.sess,
                                                         span, E0283,
@@ -1251,7 +1255,7 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if !ty.references_error() && !self.tcx.sess.has_errors() {
-                    self.need_type_info(body_id, span, ty);
+                    self.need_type_info_err(body_id, span, ty).emit();
                 }
             }
 
@@ -1262,9 +1266,9 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
                     let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
                     // both must be type variables, or the other would've been instantiated
                     assert!(a.is_ty_var() && b.is_ty_var());
-                    self.need_type_info(body_id,
-                                        obligation.cause.span,
-                                        a);
+                    self.need_type_info_err(body_id,
+                                            obligation.cause.span,
+                                            a).emit();
                 }
             }
 
@@ -1475,6 +1479,14 @@ fn note_obligation_cause_code<T>(&self,
             }
             ObligationCauseCode::ReturnType(_) |
             ObligationCauseCode::BlockTailExpression(_) => (),
+            ObligationCauseCode::TrivialBound => {
+                err.help("see issue #48214");
+                if tcx.sess.opts.unstable_features.is_nightly_build() {
+                    err.help("add #![feature(trivial_bounds)] to the \
+                              crate attributes to enable",
+                    );
+                }
+            }
         }
     }
 
index 6e20150718110ae2a0540ddf435ff1e3c64398c8..94ee39470772fe7165cb5f803d3da602aedf38a1 100644 (file)
@@ -330,7 +330,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         ty::Predicate::Trait(ref data) => {
             let trait_obligation = obligation.with(data.clone());
 
-            if data.is_global() {
+            if data.is_global() && !data.has_late_bound_regions() {
                 // no type variables present, can use evaluation for better caching.
                 // FIXME: consider caching errors too.
                 if selcx.infcx().predicate_must_hold(&obligation) {
index 10d88063ac35faea1c358253ffb82fbb42207169..f4f0c47899d4e679f2d2cffe5a77c5037a82c12b 100644 (file)
@@ -23,7 +23,7 @@
 use middle::region;
 use middle::const_val::ConstEvalErr;
 use ty::subst::Substs;
-use ty::{self, AdtKind, Slice, Ty, TyCtxt, TypeFoldable, ToPredicate};
+use ty::{self, AdtKind, Slice, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate};
 use ty::error::{ExpectedFound, TypeError};
 use infer::{InferCtxt};
 
@@ -243,6 +243,9 @@ pub enum ObligationCauseCode<'tcx> {
 
     /// Block implicit return
     BlockTailExpression(ast::NodeId),
+
+    /// #[feature(trivial_bounds)] is not enabled
+    TrivialBound,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -641,17 +644,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let predicates: Vec<_> =
         util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
-        .filter(|p| !p.is_global()) // (*)
         .collect();
 
-    // (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
-    // need to be in the *environment* to be proven, so screen those
-    // out. This is important for the soundness of inter-fn
-    // caching. Note though that we should probably check that these
-    // predicates hold at the point where the environment is
-    // constructed, but I am not currently doing so out of laziness.
-    // -nmatsakis
-
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
            predicates);
 
@@ -674,7 +668,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // we move over to lazy normalization *anyway*.
         let fulfill_cx = FulfillmentContext::new_ignoring_regions();
 
-        let predicates = match fully_normalize_with_fulfillcx(
+        let predicates = match fully_normalize(
             &infcx,
             fulfill_cx,
             cause,
@@ -734,31 +728,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                          cause: ObligationCause<'tcx>,
-                                          param_env: ty::ParamEnv<'tcx>,
-                                          value: &T)
-                                          -> Result<T, Vec<FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx>
-{
-    // FIXME (@jroesch) ISSUE 26721
-    // I'm not sure if this is a bug or not, needs further investigation.
-    // It appears that by reusing the fulfillment_cx here we incur more
-    // obligations and later trip an assertion on regionck.rs line 337.
-    //
-    // The two possibilities I see is:
-    //      - normalization is not actually fully happening and we
-    //        have a bug else where
-    //      - we are adding a duplicate bound into the list causing
-    //        its size to change.
-    //
-    // I think we should probably land this refactor and then come
-    // back to this is a follow-up patch.
-    let fulfillcx = FulfillmentContext::new();
-    fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value)
-}
-
-pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
+pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     mut fulfill_cx: FulfillmentContext<'tcx>,
     cause: ObligationCause<'tcx>,
@@ -779,13 +749,7 @@ pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
     }
 
     debug!("fully_normalize: select_all_or_error start");
-    match fulfill_cx.select_all_or_error(infcx) {
-        Ok(()) => { }
-        Err(e) => {
-            debug!("fully_normalize: error={:?}", e);
-            return Err(e);
-        }
-    }
+    fulfill_cx.select_all_or_error(infcx)?;
     debug!("fully_normalize: select_all_or_error complete");
     let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
     debug!("fully_normalize: resolved_value={:?}", resolved_value);
@@ -871,10 +835,14 @@ fn vtable_methods<'a, 'tcx>(
                 // the method may have some early-bound lifetimes, add
                 // regions for those
                 let substs = trait_ref.map_bound(|trait_ref| {
-                    Substs::for_item(
-                        tcx, def_id,
-                        |_, _| tcx.types.re_erased,
-                        |def, _| trait_ref.substs.type_for_def(def))
+                    Substs::for_item(tcx, def_id, |param, _| {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+                            GenericParamDefKind::Type(_) => {
+                                trait_ref.substs[param.index as usize]
+                            }
+                        }
+                    })
                 });
 
                 // the trait type may have higher-ranked lifetimes in it;
index c0d5a337cee3a1ca018026856bb058633e67e128..6c67c10dc69cf490dd3120bb064e5cc90ea5def4 100644 (file)
@@ -284,7 +284,7 @@ fn virtual_call_violation_for_method(self,
         }
 
         // We can't monomorphize things like `fn foo<A>(...)`.
-        if !self.generics_of(method.def_id).types.is_empty() {
+        if self.generics_of(method.def_id).own_counts().types != 0 {
             return Some(MethodViolationCode::Generic);
         }
 
@@ -387,7 +387,6 @@ fn contains_illegal_self_type_reference(self,
 }
 
 pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                         trait_def_id: DefId)
-                                         -> bool {
+                                                trait_def_id: DefId) -> bool {
     tcx.object_safety_violations(trait_def_id).is_empty()
 }
index 3cf7af30b3d551a0442f509f2a5279f2494cd5a3..539f40cf3efb5a061440bfc4c419a0837bffd5ab 100644 (file)
@@ -11,7 +11,7 @@
 use fmt_macros::{Parser, Piece, Position};
 
 use hir::def_id::DefId;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
 use util::common::ErrorReported;
 use util::nodemap::FxHashMap;
 
@@ -243,7 +243,6 @@ fn verify(&self,
         let name = tcx.item_name(trait_def_id);
         let generics = tcx.generics_of(trait_def_id);
         let parser = Parser::new(&self.0);
-        let types = &generics.types;
         let mut result = Ok(());
         for token in parser {
             match token {
@@ -254,13 +253,13 @@ fn verify(&self,
                     // `{ThisTraitsName}` is allowed
                     Position::ArgumentNamed(s) if s == name => (),
                     // So is `{A}` if A is a type parameter
-                    Position::ArgumentNamed(s) => match types.iter().find(|t| {
-                        t.name == s
+                    Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
+                        param.name == s
                     }) {
                         Some(_) => (),
                         None => {
                             span_err!(tcx.sess, span, E0230,
-                                      "there is no type parameter \
+                                      "there is no parameter \
                                        {} on trait {}",
                                       s, name);
                             result = Err(ErrorReported);
@@ -288,9 +287,15 @@ pub fn format(&self,
         let name = tcx.item_name(trait_ref.def_id);
         let trait_str = tcx.item_path_str(trait_ref.def_id);
         let generics = tcx.generics_of(trait_ref.def_id);
-        let generic_map = generics.types.iter().map(|param| {
-            (param.name.to_string(),
-             trait_ref.substs.type_for_def(param).to_string())
+        let generic_map = generics.params.iter().filter_map(|param| {
+            let value = match param.kind {
+                GenericParamDefKind::Type(_) => {
+                    trait_ref.substs[param.index as usize].to_string()
+                },
+                GenericParamDefKind::Lifetime => return None
+            };
+            let name = param.name.to_string();
+            Some((name, value))
         }).collect::<FxHashMap<String, String>>();
 
         let parser = Parser::new(&self.0);
index 3ed1e7ea5ebd65d99c7e3af6cb86be0631eb7177..bd7ec4a12b0c635df7dc4aa5206ff63acc8e66d7 100644 (file)
@@ -305,9 +305,6 @@ enum BuiltinImplConditions<'tcx> {
     /// There is no built-in impl. There may be some other
     /// candidate (a where-clause or user-defined impl).
     None,
-    /// There is *no* impl for this, builtin or not. Ignore
-    /// all where-clauses.
-    Never,
     /// It is unknown whether there is an impl.
     Ambiguous
 }
@@ -781,13 +778,13 @@ fn evaluate_trait_predicate_recursively<'o>(&mut self,
                                                 mut obligation: TraitObligation<'tcx>)
                                                 -> Result<EvaluationResult, OverflowError>
     {
-        debug!("evaluate_trait_predicate_recursively({:?})",
-               obligation);
+        debug!("evaluate_trait_predicate_recursively({:?})", obligation);
 
-        if !self.intercrate.is_some() && obligation.is_global() {
-            // If a param env is consistent, global obligations do not depend on its particular
-            // value in order to work, so we can clear out the param env and get better
-            // caching. (If the current param env is inconsistent, we don't care what happens).
+        if self.intercrate.is_none() && obligation.is_global()
+            && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) {
+            // If a param env has no global bounds, global obligations do not
+            // depend on its particular value in order to work, so we can clear
+            // out the param env and get better caching.
             debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
             obligation.param_env = obligation.param_env.without_caller_bounds();
         }
@@ -1451,22 +1448,22 @@ fn assemble_candidates<'o>(&mut self,
             let sized_conditions = self.sized_conditions(obligation);
             self.assemble_builtin_bound_candidates(sized_conditions,
                                                    &mut candidates)?;
-         } else if lang_items.unsize_trait() == Some(def_id) {
-             self.assemble_candidates_for_unsizing(obligation, &mut candidates);
-         } else {
-             if lang_items.clone_trait() == Some(def_id) {
-                 // Same builtin conditions as `Copy`, i.e. every type which has builtin support
-                 // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
-                 // types have builtin support for `Clone`.
-                 let clone_conditions = self.copy_clone_conditions(obligation);
-                 self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
-             }
-
-             self.assemble_generator_candidates(obligation, &mut candidates)?;
-             self.assemble_closure_candidates(obligation, &mut candidates)?;
-             self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
-             self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-             self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+        } else if lang_items.unsize_trait() == Some(def_id) {
+            self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+        } else {
+            if lang_items.clone_trait() == Some(def_id) {
+                // Same builtin conditions as `Copy`, i.e. every type which has builtin support
+                // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
+                // types have builtin support for `Clone`.
+                let clone_conditions = self.copy_clone_conditions(obligation);
+                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+            }
+
+            self.assemble_generator_candidates(obligation, &mut candidates)?;
+            self.assemble_closure_candidates(obligation, &mut candidates)?;
+            self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
+            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+            self.assemble_candidates_from_object_ty(obligation, &mut candidates);
         }
 
         self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
@@ -2081,13 +2078,8 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
     // BUILTIN BOUNDS
     //
     // These cover the traits that are built-in to the language
-    // itself.  This includes `Copy` and `Sized` for sure. For the
-    // moment, it also includes `Send` / `Sync` and a few others, but
-    // those will hopefully change to library-defined traits in the
-    // future.
+    // itself: `Copy`, `Clone` and `Sized`.
 
-    // HACK: if this returns an error, selection exits without considering
-    // other impls.
     fn assemble_builtin_bound_candidates<'o>(&mut self,
                                              conditions: BuiltinImplConditions<'tcx>,
                                              candidates: &mut SelectionCandidateSet<'tcx>)
@@ -2106,14 +2098,13 @@ fn assemble_builtin_bound_candidates<'o>(&mut self,
                 debug!("assemble_builtin_bound_candidates: ambiguous builtin");
                 Ok(candidates.ambiguous = true)
             }
-            BuiltinImplConditions::Never => { Err(Unimplemented) }
         }
     }
 
     fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                      -> BuiltinImplConditions<'tcx>
     {
-        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
+        use self::BuiltinImplConditions::{Ambiguous, None, Where};
 
         // NOTE: binder moved to (*)
         let self_ty = self.infcx.shallow_resolve(
@@ -2130,7 +2121,7 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                 Where(ty::Binder::dummy(Vec::new()))
             }
 
-            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
+            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => None,
 
             ty::TyTuple(tys) => {
                 Where(ty::Binder::bind(tys.last().into_iter().cloned().collect()))
@@ -2164,7 +2155,7 @@ fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
         let self_ty = self.infcx.shallow_resolve(
             obligation.predicate.skip_binder().self_ty());
 
-        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
+        use self::BuiltinImplConditions::{Ambiguous, None, Where};
 
         match self_ty.sty {
             ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
@@ -2182,7 +2173,7 @@ fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
             ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) |
             ty::TyRef(_, _, hir::MutMutable) => {
-                Never
+                None
             }
 
             ty::TyArray(element_ty, _) => {
@@ -2202,7 +2193,7 @@ fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                 if is_copy_trait || is_clone_trait {
                     Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect()))
                 } else {
-                    Never
+                    None
                 }
             }
 
index 30b2c55afa1948c5c9f24277655d78d5d15fae8e..d33806285142e4ba90de19eeac6cf240684892f0 100644 (file)
@@ -196,6 +196,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // that this always succeeds.
         let impl1_trait_ref =
             match traits::fully_normalize(&infcx,
+                                          FulfillmentContext::new(),
                                           ObligationCause::dummy(),
                                           penv,
                                           &impl1_trait_ref) {
index 822ea17009b6b0fe60abf65f1391f7862b06e105..b9593047af4159b045b154c2aef7e92002222769 100644 (file)
@@ -243,6 +243,7 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             super::IntrinsicType => Some(super::IntrinsicType),
             super::MethodReceiver => Some(super::MethodReceiver),
             super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
+            super::TrivialBound => Some(super::TrivialBound),
         }
     }
 }
index 3c62f04afc56eefcbf9944c161665c1caa8ecd77..f5a9d2a7f00145f5d510f358a8a1d7ceda1de3eb 100644 (file)
@@ -213,7 +213,7 @@ fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
                            },
 
                            Component::Param(p) => {
-                               let ty = tcx.mk_param(p.idx, p.name);
+                               let ty = tcx.mk_ty_param(p.idx, p.name);
                                Some(ty::Predicate::TypeOutlives(
                                    ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
                            },
index 4e15f0711a5aa2a6b88bc71cde1635b801215117..d911f32ed3f1f7bc227d5f08ab4854de38011233 100644 (file)
@@ -24,6 +24,7 @@
 use std::intrinsics;
 use ty::{self, Ty, TyCtxt};
 use ty::subst::Substs;
+use mir::interpret::Allocation;
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
@@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
     Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
 }
 
+#[inline]
+pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
+                                 -> Result<&'tcx Allocation, D::Error>
+    where D: TyDecoder<'a, 'tcx>,
+          'tcx: 'a,
+{
+    Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+}
+
 #[macro_export]
 macro_rules! __impl_decoder_methods {
     ($($name:ident -> $ty:ty;)*) => {
@@ -393,6 +403,15 @@ fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
                     decode_const(self)
                 }
             }
+
+            impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(
+                    &mut self
+                ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
+                    decode_allocation(self)
+                }
+            }
         }
     }
 }
index 36eb091cb6e5bcefc5d6f5b34ba14b1706e41199..3c345fcd9ee61f15cb01f60abf90ee23cef87cf2 100644 (file)
 use ich::{StableHashingContext, NodeIdHashingMode};
 use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use infer::outlives::free_region_map::FreeRegionMap;
-use middle::const_val::ConstVal;
-use middle::cstore::{CrateStore, LinkMeta};
+use middle::cstore::{CrateStoreDyn, LinkMeta};
 use middle::cstore::EncodedMetadata;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
 use mir::{self, Mir, interpret};
-use mir::interpret::{Value, PrimVal};
 use ty::subst::{Kind, Substs, Subst};
 use ty::ReprOptions;
 use ty::Instance;
@@ -46,6 +44,7 @@
 use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
+use ty::GenericParamDefKind;
 use ty::layout::{LayoutDetails, TargetDataLayout};
 use ty::maps;
 use ty::steal::Steal;
@@ -162,66 +161,65 @@ fn new(arena: &'tcx SyncDroplessArena) -> CtxtInterners<'tcx> {
         }
     }
 
-    /// Intern a type. global_interners is Some only if this is
-    /// a local interner and global_interners is its counterpart.
-    fn intern_ty(&self, st: TypeVariants<'tcx>,
-                 global_interners: Option<&CtxtInterners<'gcx>>)
-                 -> Ty<'tcx> {
-        let ty = {
-            let mut interner = self.type_.borrow_mut();
+    /// Intern a type
+    fn intern_ty(
+        local: &CtxtInterners<'tcx>,
+        global: &CtxtInterners<'gcx>,
+        st: TypeVariants<'tcx>
+    ) -> Ty<'tcx> {
+        let flags = super::flags::FlagComputation::for_sty(&st);
+
+        // HACK(eddyb) Depend on flags being accurate to
+        // determine that all contents are in the global tcx.
+        // See comments on Lift for why we can't use that.
+        if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+            let mut interner = local.type_.borrow_mut();
             if let Some(&Interned(ty)) = interner.get(&st) {
                 return ty;
             }
-            let global_interner = global_interners.map(|interners| {
-                (interners.type_.borrow_mut(), &interners.arena)
-            });
-            if let Some((ref type_, _)) = global_interner {
-                if let Some(&Interned(ty)) = type_.get(&st) {
-                    return ty;
-                }
-            }
 
-            let flags = super::flags::FlagComputation::for_sty(&st);
             let ty_struct = TyS {
                 sty: st,
                 flags: flags.flags,
                 region_depth: flags.depth,
             };
 
-            // HACK(eddyb) Depend on flags being accurate to
-            // determine that all contents are in the global tcx.
-            // See comments on Lift for why we can't use that.
-            if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
-                if let Some((mut type_, arena)) = global_interner {
-                    let ty_struct: TyS<'gcx> = unsafe {
-                        mem::transmute(ty_struct)
-                    };
-                    let ty: Ty<'gcx> = arena.alloc(ty_struct);
-                    type_.insert(Interned(ty));
-                    return ty;
-                }
-            } else {
-                // Make sure we don't end up with inference
-                // types/regions in the global tcx.
-                if global_interner.is_none() {
-                    drop(interner);
-                    bug!("Attempted to intern `{:?}` which contains \
-                          inference types/regions in the global type context",
-                         &ty_struct);
-                }
+            // Make sure we don't end up with inference
+            // types/regions in the global interner
+            if local as *const _ as usize == global as *const _ as usize {
+                bug!("Attempted to intern `{:?}` which contains \
+                    inference types/regions in the global type context",
+                    &ty_struct);
             }
 
             // Don't be &mut TyS.
-            let ty: Ty<'tcx> = self.arena.alloc(ty_struct);
+            let ty: Ty<'tcx> = local.arena.alloc(ty_struct);
             interner.insert(Interned(ty));
             ty
-        };
+        } else {
+            let mut interner = global.type_.borrow_mut();
+            if let Some(&Interned(ty)) = interner.get(&st) {
+                return ty;
+            }
 
-        debug!("Interned type: {:?} Pointer: {:?}",
-            ty, ty as *const TyS);
-        ty
-    }
+            let ty_struct = TyS {
+                sty: st,
+                flags: flags.flags,
+                region_depth: flags.depth,
+            };
+
+            // This is safe because all the types the ty_struct can point to
+            // already is in the global arena
+            let ty_struct: TyS<'gcx> = unsafe {
+                mem::transmute(ty_struct)
+            };
 
+            // Don't be &mut TyS.
+            let ty: Ty<'gcx> = global.arena.alloc(ty_struct);
+            interner.insert(Interned(ty));
+            ty
+        }
+    }
 }
 
 pub struct CommonTypes<'tcx> {
@@ -796,7 +794,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
-        let mk = |sty| interners.intern_ty(sty, None);
+        let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
         let mk_region = |r| {
             if let Some(r) = interners.region.borrow().get(&r) {
                 return r.0;
@@ -855,7 +853,7 @@ pub struct GlobalCtxt<'tcx> {
     global_arenas: &'tcx GlobalArenas<'tcx>,
     global_interners: CtxtInterners<'tcx>,
 
-    cstore: &'tcx dyn CrateStore,
+    cstore: &'tcx CrateStoreDyn,
 
     pub sess: &'tcx Session,
 
@@ -1132,7 +1130,7 @@ pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId {
             return alloc_id;
         }
         // create an allocation that just contains these bytes
-        let alloc = interpret::Allocation::from_bytes(bytes);
+        let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
         let alloc = self.intern_const_alloc(alloc);
 
         // the next unique id
@@ -1191,7 +1189,7 @@ fn is_global(self) -> bool {
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
     /// reference to the context, to allow formatting values that need it.
     pub fn create_and_enter<F, R>(s: &'tcx Session,
-                                  cstore: &'tcx dyn CrateStore,
+                                  cstore: &'tcx CrateStoreDyn,
                                   local_providers: ty::maps::Providers<'tcx>,
                                   extern_providers: ty::maps::Providers<'tcx>,
                                   arenas: &'tcx AllArenas<'tcx>,
@@ -1803,9 +1801,11 @@ fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter) -> fmt::Result {
     /// in librustc otherwise. It is used to when diagnostic messages are
     /// emitted and stores them in the current query, if there is one.
     fn track_diagnostic(diagnostic: &Diagnostic) {
-        with_context(|context| {
-            if let Some(ref query) = context.query {
-                query.diagnostics.lock().push(diagnostic.clone());
+        with_context_opt(|icx| {
+            if let Some(icx) = icx {
+                if let Some(ref query) = icx.query {
+                    query.diagnostics.lock().push(diagnostic.clone());
+                }
             }
         })
     }
@@ -2130,31 +2130,17 @@ macro_rules! intern_method {
                                             $keep_in_local_tcx:expr) -> $ty:ty) => {
         impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
             pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
-                {
-                    let key = ($alloc_to_key)(&v);
-                    if let Some(i) = self.interners.$name.borrow().get(key) {
-                        return i.0;
-                    }
-                    if !self.is_global() {
-                        if let Some(i) = self.global_interners.$name.borrow().get(key) {
-                            return i.0;
-                        }
-                    }
-                }
+                let key = ($alloc_to_key)(&v);
 
                 // HACK(eddyb) Depend on flags being accurate to
                 // determine that all contents are in the global tcx.
                 // See comments on Lift for why we can't use that.
-                if !($keep_in_local_tcx)(&v) {
-                    if !self.is_global() {
-                        let v = unsafe {
-                            mem::transmute(v)
-                        };
-                        let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
-                        self.global_interners.$name.borrow_mut().insert(Interned(i));
-                        return i;
+                if ($keep_in_local_tcx)(&v) {
+                    let mut interner = self.interners.$name.borrow_mut();
+                    if let Some(&Interned(v)) = interner.get(key) {
+                        return v;
                     }
-                } else {
+
                     // Make sure we don't end up with inference
                     // types/regions in the global tcx.
                     if self.is_global() {
@@ -2162,11 +2148,24 @@ pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
                               inference types/regions in the global type context",
                              v);
                     }
-                }
 
-                let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
-                self.interners.$name.borrow_mut().insert(Interned(i));
-                i
+                    let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
+                    interner.insert(Interned(i));
+                    i
+                } else {
+                    let mut interner = self.global_interners.$name.borrow_mut();
+                    if let Some(&Interned(v)) = interner.get(key) {
+                        return v;
+                    }
+
+                    // This transmutes $alloc<'tcx> to $alloc<'gcx>
+                    let v = unsafe {
+                        mem::transmute(v)
+                    };
+                    let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
+                    interner.insert(Interned(i));
+                    i
+                }
             }
         }
     }
@@ -2274,15 +2273,8 @@ pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_fn_ptr(converted_sig)
     }
 
-    // Interns a type/name combination, stores the resulting box in cx.interners,
-    // and returns the box as cast to an unsafe ptr (see comments for Ty above).
-    pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
-        let global_interners = if !self.is_global() {
-            Some(&self.global_interners)
-        } else {
-            None
-        };
-        self.interners.intern_ty(st, global_interners)
+    pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+        CtxtInterners::intern_ty(&self.interners, &self.global_interners, st)
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
@@ -2334,15 +2326,19 @@ pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
     pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
         let adt_def = self.adt_def(def_id);
-        let generics = self.generics_of(def_id);
-        let mut substs = vec![Kind::from(ty)];
-        // Add defaults for other generic params if there are some.
-        for def in generics.types.iter().skip(1) {
-            assert!(def.has_default);
-            let ty = self.type_of(def.def_id).subst(self, &substs);
-            substs.push(ty.into());
-        }
-        let substs = self.mk_substs(substs.into_iter());
+        let substs = Substs::for_item(self, def_id, |param, substs| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => bug!(),
+                GenericParamDefKind::Type(ty_param) => {
+                    if param.index == 0 {
+                        ty.into()
+                    } else {
+                        assert!(ty_param.has_default);
+                        self.type_of(param.def_id).subst(self, substs).into()
+                    }
+                }
+            }
+        });
         self.mk_ty(TyAdt(adt_def, substs))
     }
 
@@ -2375,10 +2371,7 @@ pub fn mk_nil_ptr(self) -> Ty<'tcx> {
     }
 
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
-            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
-            ty: self.types.usize
-        })))
+        self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
     }
 
     pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -2469,18 +2462,23 @@ pub fn mk_infer(self, it: InferTy) -> Ty<'tcx> {
         self.mk_ty(TyInfer(it))
     }
 
-    pub fn mk_param(self,
+    pub fn mk_ty_param(self,
                     index: u32,
                     name: InternedString) -> Ty<'tcx> {
         self.mk_ty(TyParam(ParamTy { idx: index, name: name }))
     }
 
     pub fn mk_self_type(self) -> Ty<'tcx> {
-        self.mk_param(0, keywords::SelfType.name().as_interned_str())
+        self.mk_ty_param(0, keywords::SelfType.name().as_interned_str())
     }
 
-    pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
-        self.mk_param(def.index, def.name)
+    pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> {
+        match param.kind {
+            GenericParamDefKind::Lifetime => {
+                self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
+            }
+            GenericParamDefKind::Type(_) => self.mk_ty_param(param.index, param.name).into(),
+        }
     }
 
     pub fn mk_anon(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
index cfde35de93c3b1ac2963dd0186bb2b628d74f93a..7dfdc592647dbafaa7cdd610c1dcbf60abc5983d 100644 (file)
@@ -182,7 +182,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
             ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
             ty::TyArray(_, n) => {
-                match n.val.to_raw_bits() {
+                match n.assert_usize(tcx) {
                     Some(n) => format!("array of {} elements", n),
                     None => "array".to_string(),
                 }
index 01de848e0f076b077010336b17cf02ec42eba7e8..e913f8f568adab3ecb0a07747bee4ba01c5a1b67 100644 (file)
@@ -79,7 +79,7 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
             }
 
             &ty::TyParam(ref p) => {
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                 if p.is_self() {
                     self.add_flags(TypeFlags::HAS_SELF);
                 } else {
@@ -89,7 +89,7 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
 
             &ty::TyGenerator(_, ref substs, _) => {
                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                 self.add_substs(&substs.substs);
             }
 
@@ -101,12 +101,12 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
 
             &ty::TyClosure(_, ref substs) => {
                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                 self.add_substs(&substs.substs);
             }
 
             &ty::TyInfer(infer) => {
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
+                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
                 self.add_flags(TypeFlags::HAS_TY_INFER);
                 match infer {
                     ty::FreshTy(_) |
index 1793b5e1edba8e0f3ca76ee956775bd8bb82cb1e..a1f9fd76b02dcefd79a9b55fc047414336e0b801 100644 (file)
@@ -116,10 +116,14 @@ fn has_erasable_regions(&self) -> bool {
 
     /// Indicates whether this value references only 'global'
     /// types/lifetimes that are the same regardless of what fn we are
-    /// in. This is used for caching. Errs on the side of returning
-    /// false.
+    /// in. This is used for caching.
     fn is_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
+        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+    }
+
+    /// True if there are any late-bound regions
+    fn has_late_bound_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
     }
 }
 
index 17a3d0011eddfe5276eadb910ff9dc214583568f..19e5406cd0d0a0aadf1d14224914d7280cac8dcb 100644 (file)
@@ -262,7 +262,7 @@ fn uninhabited_from(
                 }))
             },
             TyArray(ty, len) => {
-                match len.val.to_raw_bits() {
+                match len.assert_usize(tcx) {
                     // If the array is definitely non-empty, it's uninhabited if
                     // the type of its elements is uninhabited.
                     Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
index 0688dcabe5585db0d83089b372f918c30b07dbb3..bbfc6d883e9ae7d0d989d98abc0eeaeffa37072c 100644 (file)
@@ -325,10 +325,6 @@ enum StructKind {
                         offsets.len(), ty);
                 }
 
-                if field.abi == Abi::Uninhabited {
-                    return Ok(LayoutDetails::uninhabited(fields.len()));
-                }
-
                 if field.is_unsized() {
                     sized = false;
                 }
@@ -451,6 +447,10 @@ enum StructKind {
                 }
             }
 
+            if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+                abi = Abi::Uninhabited;
+            }
+
             Ok(LayoutDetails {
                 variants: Variants::Single { index: 0 },
                 fields: FieldPlacement::Arbitrary {
@@ -497,7 +497,13 @@ enum StructKind {
 
             // The never type.
             ty::TyNever => {
-                tcx.intern_layout(LayoutDetails::uninhabited(0))
+                tcx.intern_layout(LayoutDetails {
+                    variants: Variants::Single { index: 0 },
+                    fields: FieldPlacement::Union(0),
+                    abi: Abi::Uninhabited,
+                    align: dl.i8_align,
+                    size: Size::from_bytes(0)
+                })
             }
 
             // Potentially-fat pointers.
@@ -543,7 +549,7 @@ enum StructKind {
                 }
 
                 let element = self.layout_of(element)?;
-                let count = count.val.unwrap_u64();
+                let count = count.unwrap_usize(tcx);
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
@@ -711,27 +717,37 @@ enum StructKind {
                     }));
                 }
 
-                let (inh_first, inh_second) = {
-                    let mut inh_variants = (0..variants.len()).filter(|&v| {
-                        variants[v].iter().all(|f| f.abi != Abi::Uninhabited)
+                // A variant is absent if it's uninhabited and only has ZST fields.
+                // Present uninhabited variants only require space for their fields,
+                // but *not* an encoding of the discriminant (e.g. a tag value).
+                // See issue #49298 for more details on the need to leave space
+                // for non-ZST uninhabited data (mostly partial initialization).
+                let absent = |fields: &[TyLayout]| {
+                    let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited);
+                    let is_zst = fields.iter().all(|f| f.is_zst());
+                    uninhabited && is_zst
+                };
+                let (present_first, present_second) = {
+                    let mut present_variants = (0..variants.len()).filter(|&v| {
+                        !absent(&variants[v])
                     });
-                    (inh_variants.next(), inh_variants.next())
+                    (present_variants.next(), present_variants.next())
                 };
-                if inh_first.is_none() {
-                    // Uninhabited because it has no variants, or only uninhabited ones.
-                    return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0)));
+                if present_first.is_none() {
+                    // Uninhabited because it has no variants, or only absent ones.
+                    return tcx.layout_raw(param_env.and(tcx.types.never));
                 }
 
                 let is_struct = !def.is_enum() ||
-                    // Only one variant is inhabited.
-                    (inh_second.is_none() &&
+                    // Only one variant is present.
+                    (present_second.is_none() &&
                     // Representation optimizations are allowed.
                      !def.repr.inhibit_enum_layout_opt());
                 if is_struct {
                     // Struct, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
-                    let v = inh_first.unwrap();
+                    let v = present_first.unwrap();
                     let kind = if def.is_enum() || variants[v].len() == 0 {
                         StructKind::AlwaysSized
                     } else {
@@ -773,7 +789,7 @@ enum StructKind {
 
                     // Find one non-ZST variant.
                     'variants: for (v, fields) in variants.iter().enumerate() {
-                        if fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+                        if absent(fields) {
                             continue 'variants;
                         }
                         for f in fields {
@@ -816,7 +832,7 @@ enum StructKind {
                             let offset = st[i].fields.offset(field_index) + offset;
                             let size = st[i].size;
 
-                            let abi = match st[i].abi {
+                            let mut abi = match st[i].abi {
                                 Abi::Scalar(_) => Abi::Scalar(niche.clone()),
                                 Abi::ScalarPair(ref first, ref second) => {
                                     // We need to use scalar_unit to reset the
@@ -833,6 +849,10 @@ enum StructKind {
                                 _ => Abi::Aggregate { sized: true },
                             };
 
+                            if st.iter().all(|v| v.abi == Abi::Uninhabited) {
+                                abi = Abi::Uninhabited;
+                            }
+
                             return Ok(tcx.intern_layout(LayoutDetails {
                                 variants: Variants::NicheFilling {
                                     dataful_variant: i,
@@ -868,6 +888,11 @@ enum StructKind {
                     if x < min { min = x; }
                     if x > max { max = x; }
                 }
+                // We might have no inhabited variants, so pretend there's at least one.
+                if (min, max) == (i128::max_value(), i128::min_value()) {
+                    min = 0;
+                    max = 0;
+                }
                 assert!(min <= max, "discriminant range is {}...{}", min, max);
                 let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
 
@@ -959,9 +984,6 @@ enum StructKind {
                     let old_ity_size = min_ity.size();
                     let new_ity_size = ity.size();
                     for variant in &mut layout_variants {
-                        if variant.abi == Abi::Uninhabited {
-                            continue;
-                        }
                         match variant.fields {
                             FieldPlacement::Arbitrary { ref mut offsets, .. } => {
                                 for i in offsets {
@@ -1055,6 +1077,11 @@ enum StructKind {
                         }
                     }
                 }
+
+                if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) {
+                    abi = Abi::Uninhabited;
+                }
+
                 tcx.intern_layout(LayoutDetails {
                     variants: Variants::Tagged {
                         tag,
@@ -1523,9 +1550,14 @@ fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'t
                     ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
                     _ => bug!()
                 };
-                let mut details = LayoutDetails::uninhabited(fields);
-                details.variants = Variants::Single { index: variant_index };
-                cx.tcx().intern_layout(details)
+                let tcx = cx.tcx();
+                tcx.intern_layout(LayoutDetails {
+                    variants: Variants::Single { index: variant_index },
+                    fields: FieldPlacement::Union(fields),
+                    abi: Abi::Uninhabited,
+                    align: tcx.data_layout.i8_align,
+                    size: Size::from_bytes(0)
+                })
             }
 
             Variants::NicheFilling { ref variants, .. } |
index 57c8c4f34e70e66c72ad4a8724972d8a989d6f74..ad48519e136c8eae12f77fc758adcbd38f49a31a 100644 (file)
@@ -11,7 +11,7 @@
 use dep_graph::SerializedDepNodeIndex;
 use dep_graph::DepNode;
 use hir::def_id::{CrateNum, DefId, DefIndex};
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
 use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
 use ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::Substs;
@@ -137,6 +137,12 @@ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
+    fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
+        format!("converting value `{:?}` ({}) to an allocation", val, ty)
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
     fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
         format!("erasing regions from `{:?}`", ty)
@@ -537,7 +543,7 @@ fn describe(_tcx: TyCtxt, _: DefIndex) -> String {
 
 impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> {
     fn describe(_tcx: TyCtxt, _: DefIndex) -> String {
-        format!("testing if a region is late boudn")
+        format!("testing if a region is late bound")
     }
 }
 
index da29f23589e85e7a5f464cc5d325d1fbc8b49787..3510a1b7a028f55a04d4ded97028b1a8fe47bde1 100644 (file)
@@ -145,6 +145,15 @@ fn default_span(&self, tcx: TyCtxt) -> Span {
     }
 }
 
+impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for Ty<'tcx> {
     fn map_crate(&self) -> CrateNum {
         LOCAL_CRATE
index d89846a75ef51a8050c0af043e60045f2830666f..6e419627dd8b5bfe6ed04ecd6fac754fdb18c0f4 100644 (file)
@@ -28,7 +28,7 @@
 use middle::const_val::EvalResult;
 use mir::mono::{CodegenUnit, Stats};
 use mir;
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, Allocation, ConstValue};
 use session::{CompileResult, CrateDisambiguator};
 use session::config::OutputFilenames;
 use traits::{self, Vtable};
     [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
         -> EvalResult<'tcx>,
 
+    /// Converts a constant value to an constant allocation
+    [] fn const_value_to_allocation: const_value_to_allocation(
+        (ConstValue<'tcx>, Ty<'tcx>)
+    ) -> &'tcx Allocation,
+
     [] fn check_match: CheckMatch(DefId)
         -> Result<(), ErrorReported>,
 
@@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
     DepConstructor::EraseRegionsTy { ty }
 }
 
+fn const_value_to_allocation<'tcx>(
+    (val, ty): (ConstValue<'tcx>, Ty<'tcx>)
+) -> DepConstructor<'tcx> {
+    DepConstructor::ConstValueToAllocation { val, ty }
+}
+
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
     DepConstructor::TypeParamPredicates {
         item_id,
index 37950463f74446d1f9b486224e416832a04e8f9b..65dcb7311d336fd76885afc62aa53c50be118b50 100644 (file)
@@ -956,6 +956,7 @@ macro_rules! force {
         DepKind::FulfillObligation |
         DepKind::VtableMethods |
         DepKind::EraseRegionsTy |
+        DepKind::ConstValueToAllocation |
         DepKind::NormalizeProjectionTy |
         DepKind::NormalizeTyAfterErasingRegions |
         DepKind::DropckOutlives |
index 7076112e3715a285b6377140e3319d40332fcff3..eb638d7c9a1a8aee70a2eb9cf6a2d0508ba31da5 100644 (file)
 use ich::Fingerprint;
 use ich::StableHashingContext;
 use infer::canonical::{Canonical, Canonicalize};
-use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
 use mir::GeneratorLayout;
 use session::CrateDisambiguator;
 use traits::{self, Reveal};
@@ -442,7 +441,7 @@ pub struct TypeFlags: u32 {
 
         // true if there are "names" of types and regions and so forth
         // that are local to a particular fn
-        const HAS_LOCAL_NAMES    = 1 << 10;
+        const HAS_FREE_LOCAL_NAMES    = 1 << 10;
 
         // Present if the type belongs in a local type context.
         // Only set for TyInfer other than Fresh.
@@ -456,6 +455,10 @@ pub struct TypeFlags: u32 {
         // ought to be true only for the results of canonicalization.
         const HAS_CANONICAL_VARS = 1 << 13;
 
+        /// Does this have any `ReLateBound` regions? Used to check
+        /// if a global bound is safe to evaluate.
+        const HAS_RE_LATE_BOUND = 1 << 14;
+
         const NEEDS_SUBST        = TypeFlags::HAS_PARAMS.bits |
                                    TypeFlags::HAS_SELF.bits |
                                    TypeFlags::HAS_RE_EARLY_BOUND.bits;
@@ -473,9 +476,10 @@ pub struct TypeFlags: u32 {
                                   TypeFlags::HAS_TY_ERR.bits |
                                   TypeFlags::HAS_PROJECTION.bits |
                                   TypeFlags::HAS_TY_CLOSURE.bits |
-                                  TypeFlags::HAS_LOCAL_NAMES.bits |
+                                  TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
                                   TypeFlags::KEEP_IN_LOCAL_TCX.bits |
-                                  TypeFlags::HAS_CANONICAL_VARS.bits;
+                                  TypeFlags::HAS_CANONICAL_VARS.bits |
+                                  TypeFlags::HAS_RE_LATE_BOUND.bits;
     }
 }
 
@@ -710,148 +714,152 @@ pub enum IntVarValue {
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub struct FloatVarValue(pub ast::FloatTy);
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct TypeParameterDef {
-    pub name: InternedString,
-    pub def_id: DefId,
-    pub index: u32,
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub struct TypeParamDef {
     pub has_default: bool,
     pub object_lifetime_default: ObjectLifetimeDefault,
+    pub synthetic: Option<hir::SyntheticTyParamKind>,
+}
 
-    /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
-    /// on generic parameter `T`, asserts data behind the parameter
-    /// `T` won't be accessed during the parent type's `Drop` impl.
-    pub pure_wrt_drop: bool,
+impl ty::EarlyBoundRegion {
+    pub fn to_bound_region(&self) -> ty::BoundRegion {
+        ty::BoundRegion::BrNamed(self.def_id, self.name)
+    }
+}
 
-    pub synthetic: Option<hir::SyntheticTyParamKind>,
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum GenericParamDefKind {
+    Lifetime,
+    Type(TypeParamDef),
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct RegionParameterDef {
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct GenericParamDef {
     pub name: InternedString,
     pub def_id: DefId,
     pub index: u32,
 
     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
-    /// on generic parameter `'a`, asserts data of lifetime `'a`
-    /// won't be accessed during the parent type's `Drop` impl.
+    /// on generic parameter `'a`/`T`, asserts data behind the parameter
+    /// `'a`/`T` won't be accessed during the parent type's `Drop` impl.
     pub pure_wrt_drop: bool,
+
+    pub kind: GenericParamDefKind,
 }
 
-impl RegionParameterDef {
+impl GenericParamDef {
     pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
-        ty::EarlyBoundRegion {
-            def_id: self.def_id,
-            index: self.index,
-            name: self.name,
+        match self.kind {
+            GenericParamDefKind::Lifetime => {
+                ty::EarlyBoundRegion {
+                    def_id: self.def_id,
+                    index: self.index,
+                    name: self.name,
+                }
+            }
+            _ => bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
 
     pub fn to_bound_region(&self) -> ty::BoundRegion {
-        self.to_early_bound_region_data().to_bound_region()
+        match self.kind {
+            GenericParamDefKind::Lifetime => {
+                self.to_early_bound_region_data().to_bound_region()
+            }
+            _ => bug!("cannot convert a non-lifetime parameter def to an early bound region")
+        }
     }
 }
 
-impl ty::EarlyBoundRegion {
-    pub fn to_bound_region(&self) -> ty::BoundRegion {
-        ty::BoundRegion::BrNamed(self.def_id, self.name)
-    }
+pub struct GenericParamCount {
+    pub lifetimes: usize,
+    pub types: usize,
 }
 
 /// Information about the formal type/lifetime parameters associated
 /// with an item or method. Analogous to hir::Generics.
 ///
-/// Note that in the presence of a `Self` parameter, the ordering here
-/// is different from the ordering in a Substs. Substs are ordered as
-///     Self, *Regions, *Other Type Params, (...child generics)
-/// while this struct is ordered as
-///     regions = Regions
-///     types = [Self, *Other Type Params]
+/// The ordering of parameters is the same as in Subst (excluding child generics):
+/// Self (optionally), Lifetime params..., Type params...
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Generics {
     pub parent: Option<DefId>,
-    pub parent_regions: u32,
-    pub parent_types: u32,
-    pub regions: Vec<RegionParameterDef>,
-    pub types: Vec<TypeParameterDef>,
+    pub parent_count: usize,
+    pub params: Vec<GenericParamDef>,
 
-    /// Reverse map to each `TypeParameterDef`'s `index` field
-    pub type_param_to_index: FxHashMap<DefId, u32>,
+    /// Reverse map to the `index` field of each `GenericParamDef`
+    pub param_def_id_to_index: FxHashMap<DefId, u32>,
 
     pub has_self: bool,
     pub has_late_bound_regions: Option<Span>,
 }
 
 impl<'a, 'gcx, 'tcx> Generics {
-    pub fn parent_count(&self) -> usize {
-        self.parent_regions as usize + self.parent_types as usize
+    pub fn count(&self) -> usize {
+        self.parent_count + self.params.len()
     }
 
-    pub fn own_count(&self) -> usize {
-        self.regions.len() + self.types.len()
+    pub fn own_counts(&self) -> GenericParamCount {
+        // We could cache this as a property of `GenericParamCount`, but
+        // the aim is to refactor this away entirely eventually and the
+        // presence of this method will be a constant reminder.
+        let mut own_counts = GenericParamCount {
+            lifetimes: 0,
+            types: 0,
+        };
+
+        for param in &self.params {
+            match param.kind {
+                GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
+                GenericParamDefKind::Type(_) => own_counts.types += 1,
+            };
+        }
+
+        own_counts
     }
 
-    pub fn count(&self) -> usize {
-        self.parent_count() + self.own_count()
+    pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        for param in &self.params {
+            match param.kind {
+                GenericParamDefKind::Type(_) => return true,
+                GenericParamDefKind::Lifetime => {}
+            }
+        }
+        if let Some(parent_def_id) = self.parent {
+            let parent = tcx.generics_of(parent_def_id);
+            parent.requires_monomorphization(tcx)
+        } else {
+            false
+        }
     }
 
     pub fn region_param(&'tcx self,
                         param: &EarlyBoundRegion,
                         tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                        -> &'tcx RegionParameterDef
+                        -> &'tcx GenericParamDef
     {
-        if let Some(index) = param.index.checked_sub(self.parent_count() as u32) {
-            &self.regions[index as usize - self.has_self as usize]
+        if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
+            let param = &self.params[index as usize];
+            match param.kind {
+                ty::GenericParamDefKind::Lifetime => param,
+                _ => bug!("expected lifetime parameter, but found another generic parameter")
+            }
         } else {
             tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
                 .region_param(param, tcx)
         }
     }
 
-    /// Returns the `TypeParameterDef` associated with this `ParamTy`.
+    /// Returns the `TypeParamDef` associated with this `ParamTy`.
     pub fn type_param(&'tcx self,
                       param: &ParamTy,
                       tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                      -> &TypeParameterDef {
-        if let Some(idx) = param.idx.checked_sub(self.parent_count() as u32) {
-            // non-Self type parameters are always offset by exactly
-            // `self.regions.len()`. In the absence of a Self, this is obvious,
-            // but even in the presence of a `Self` we just have to "compensate"
-            // for the regions:
-            //
-            // Without a `Self` (or in a nested generics that doesn't have
-            // a `Self` in itself, even through it parent does), for example
-            // for `fn foo<'a, T1, T2>()`, the situation is:
-            //     Substs:
-            //         0  1  2
-            //         'a T1 T2
-            //     generics.types:
-            //         0  1
-            //         T1 T2
-            //
-            // And with a `Self`, for example for `trait Foo<'a, 'b, T1, T2>`, the
-            // situation is:
-            //     Substs:
-            //         0   1  2  3  4
-            //       Self 'a 'b  T1 T2
-            //     generics.types:
-            //         0  1  2
-            //       Self T1 T2
-            //
-            // And it can be seen that in both cases, to move from a substs
-            // offset to a generics offset you just have to offset by the
-            // number of regions.
-            let type_param_offset = self.regions.len();
-
-            let has_self = self.has_self && self.parent.is_none();
-            let is_separated_self = type_param_offset != 0 && idx == 0 && has_self;
-
-            if let Some(idx) = (idx as usize).checked_sub(type_param_offset) {
-                assert!(!is_separated_self, "found a Self after type_param_offset");
-                &self.types[idx]
-            } else {
-                assert!(is_separated_self, "non-Self param before type_param_offset");
-                &self.types[0]
+                      -> &'tcx GenericParamDef {
+        if let Some(index) = param.idx.checked_sub(self.parent_count as u32) {
+            let param = &self.params[index as usize];
+            match param.kind {
+                ty::GenericParamDefKind::Type(_) => param,
+                _ => bug!("expected type parameter, but found another generic parameter")
             }
         } else {
             tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
@@ -1933,27 +1941,23 @@ pub fn eval_explicit_discr(
             promoted: None
         };
         match tcx.const_eval(param_env.and(cid)) {
-            Ok(&ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
-                ty,
-            }) => {
-                trace!("discriminants: {} ({:?})", b, repr_type);
-                Some(Discr {
-                    val: b,
-                    ty,
-                })
-            },
-            Ok(&ty::Const {
-                val: ConstVal::Value(other),
-                ..
-            }) => {
-                info!("invalid enum discriminant: {:#?}", other);
-                ::middle::const_val::struct_error(
-                    tcx,
-                    tcx.def_span(expr_did),
-                    "constant evaluation of enum discriminant resulted in non-integer",
-                ).emit();
-                None
+            Ok(val) => {
+                // FIXME: Find the right type and use it instead of `val.ty` here
+                if let Some(b) = val.assert_bits(val.ty) {
+                    trace!("discriminants: {} ({:?})", b, repr_type);
+                    Some(Discr {
+                        val: b,
+                        ty: val.ty,
+                    })
+                } else {
+                    info!("invalid enum discriminant: {:#?}", val);
+                    ::middle::const_val::struct_error(
+                        tcx,
+                        tcx.def_span(expr_did),
+                        "constant evaluation of enum discriminant resulted in non-integer",
+                    ).emit();
+                    None
+                }
             }
             Err(err) => {
                 err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
@@ -1964,7 +1968,6 @@ pub fn eval_explicit_discr(
                 }
                 None
             }
-            _ => span_bug!(tcx.def_span(expr_did), "const eval "),
         }
     }
 
index 109dfebf154de67730d3e0294d5cf092af1dee30..4a33f1a1f54d2d268bfa3c2319e28fa0aa46780f 100644 (file)
@@ -18,7 +18,7 @@
 use ty::subst::{Kind, UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
 use util::common::ErrorReported;
 use std::rc::Rc;
 use std::iter;
@@ -469,8 +469,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             assert_eq!(sz_a.ty, tcx.types.usize);
             assert_eq!(sz_b.ty, tcx.types.usize);
             let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
+                if let Some(s) = x.assert_usize(tcx) {
+                    return Ok(s);
+                }
                 match x.val {
-                    ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
                     ConstVal::Unevaluated(def_id, substs) => {
                         // FIXME(eddyb) get the right param_env.
                         let param_env = ty::ParamEnv::empty();
@@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                         instance,
                                         promoted: None
                                     };
-                                    match tcx.const_eval(param_env.and(cid)) {
-                                        Ok(&ty::Const {
-                                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
-                                            ..
-                                        }) => {
-                                            assert_eq!(b as u64 as u128, b);
-                                            return Ok(b as u64);
-                                        }
-                                        _ => {}
+                                    if let Some(s) = tcx.const_eval(param_env.and(cid))
+                                                        .ok()
+                                                        .map(|c| c.unwrap_usize(tcx)) {
+                                        return Ok(s)
                                     }
                                 }
                             },
index 7518f008fb316515be6f8b4ce65e1f2ffe442b6d..5c0217fc3f51e2cb3c5c080306b4b054240610e3 100644 (file)
@@ -19,6 +19,7 @@
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use ty::{Slice, TyS};
 use util::captures::Captures;
+use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
 
 use std::iter;
 use std::cmp::Ordering;
@@ -291,7 +292,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
     /// ordering.
     fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitClosureSubsts<'tcx> {
         let generics = tcx.generics_of(def_id);
-        let parent_len = generics.parent_count();
+        let parent_len = generics.parent_count;
         SplitClosureSubsts {
             closure_kind_ty: self.substs.type_at(parent_len),
             closure_sig_ty: self.substs.type_at(parent_len + 1),
@@ -365,7 +366,7 @@ struct SplitGeneratorSubsts<'tcx> {
 impl<'tcx> GeneratorSubsts<'tcx> {
     fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitGeneratorSubsts<'tcx> {
         let generics = tcx.generics_of(def_id);
-        let parent_len = generics.parent_count();
+        let parent_len = generics.parent_count;
         SplitGeneratorSubsts {
             yield_ty: self.substs.type_at(parent_len),
             return_ty: self.substs.type_at(parent_len + 1),
@@ -927,12 +928,12 @@ pub fn for_self() -> ParamTy {
         ParamTy::new(0, keywords::SelfType.name().as_interned_str())
     }
 
-    pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy {
+    pub fn for_def(def: &ty::GenericParamDef) -> ParamTy {
         ParamTy::new(def.index, def.name)
     }
 
     pub fn to_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        tcx.mk_param(self.idx, self.name)
+        tcx.mk_ty_param(self.idx, self.name)
     }
 
     pub fn is_self(&self) -> bool {
@@ -1267,7 +1268,9 @@ pub fn type_flags(&self) -> TypeFlags {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_SKOL;
             }
-            ty::ReLateBound(..) => { }
+            ty::ReLateBound(..) => {
+                flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
+            }
             ty::ReEarlyBound(..) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
@@ -1290,8 +1293,8 @@ pub fn type_flags(&self) -> TypeFlags {
         }
 
         match *self {
-            ty::ReStatic | ty::ReEmpty | ty::ReErased => (),
-            _ => flags = flags | TypeFlags::HAS_LOCAL_NAMES,
+            ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (),
+            _ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES,
         }
 
         debug!("type_flags({:?}) = {:?}", self, flags);
@@ -1730,4 +1733,156 @@ pub struct Const<'tcx> {
     pub val: ConstVal<'tcx>,
 }
 
+impl<'tcx> Const<'tcx> {
+    pub fn unevaluated(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        def_id: DefId,
+        substs: &'tcx Substs<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        tcx.mk_const(Const {
+            val: ConstVal::Unevaluated(def_id, substs),
+            ty,
+        })
+    }
+
+    #[inline]
+    pub fn from_const_val(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: ConstVal<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        tcx.mk_const(Const {
+            val,
+            ty,
+        })
+    }
+
+    #[inline]
+    pub fn from_const_value(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_val(tcx, ConstVal::Value(val), ty)
+    }
+
+    #[inline]
+    pub fn from_alloc(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        alloc: &'tcx Allocation,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
+    }
+
+    #[inline]
+    pub fn from_byval_value(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: Value,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
+    }
+
+    #[inline]
+    pub fn from_primval(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: PrimVal,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::from_primval(val), ty)
+    }
+
+    #[inline]
+    pub fn from_bits(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: u128,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_primval(tcx, PrimVal::Bytes(val), ty)
+    }
+
+    #[inline]
+    pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+        Self::from_primval(tcx, PrimVal::Undef, ty)
+    }
+
+    #[inline]
+    pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
+        Self::from_bits(tcx, v as u128, tcx.types.bool)
+    }
+
+    #[inline]
+    pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
+        Self::from_bits(tcx, n as u128, tcx.types.usize)
+    }
+
+    #[inline]
+    pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
+        if self.ty != ty {
+            return None;
+        }
+        match self.val {
+            ConstVal::Value(val) => val.to_bits(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_ptr(&self) -> Option<MemoryPointer> {
+        match self.val {
+            ConstVal::Value(val) => val.to_ptr(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_primval(&self) -> Option<PrimVal> {
+        match self.val {
+            ConstVal::Value(val) => val.to_primval(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
+        assert_eq!(self.ty, ty);
+        match self.val {
+            ConstVal::Value(val) => val.to_bits(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
+        self.assert_bits(tcx.types.bool).and_then(|v| match v {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        })
+    }
+
+    #[inline]
+    pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
+        self.assert_bits(tcx.types.usize).map(|v| v as u64)
+    }
+
+    #[inline]
+    pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
+        match self.assert_bits(ty) {
+            Some(val) => val,
+            None => bug!("expected bits of {}, got {:#?}", ty, self),
+        }
+    }
+
+    #[inline]
+    pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
+        match self.assert_usize(tcx) {
+            Some(val) => val,
+            None => bug!("expected constant usize, got {:#?}", self),
+        }
+    }
+}
+
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
index e7b58ae1564aa1683a86a36d92c5ee81eae26a47..b94b3e17f862fb29f2edcc4aad42c4e7ddbe4c19 100644 (file)
@@ -174,92 +174,72 @@ fn decode<D: Decoder>(d: &mut D) -> Result<Kind<'tcx>, D::Error> {
     }
 }
 
-/// A substitution mapping type/region parameters to new values.
+/// A substitution mapping generic parameters to new values.
 pub type Substs<'tcx> = Slice<Kind<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     /// Creates a Substs that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId)
                              -> &'tcx Substs<'tcx> {
-        Substs::for_item(tcx, def_id, |def, _| {
-            tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-        }, |def, _| tcx.mk_param_from_def(def))
+        Substs::for_item(tcx, def_id, |param, _| {
+            tcx.mk_param_from_def(param)
+        })
     }
 
     /// Creates a Substs for generic parameter definitions,
-    /// by calling closures to obtain each region and type.
+    /// by calling closures to obtain each kind.
     /// The closures get to observe the Substs as they're
     /// being built, which can be used to correctly
-    /// substitute defaults of type parameters.
-    pub fn for_item<FR, FT>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                            def_id: DefId,
-                            mut mk_region: FR,
-                            mut mk_type: FT)
-                            -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+    /// substitute defaults of generic parameters.
+    pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                       def_id: DefId,
+                       mut mk_kind: F)
+                       -> &'tcx Substs<'tcx>
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+    {
         let defs = tcx.generics_of(def_id);
         let mut substs = Vec::with_capacity(defs.count());
-        Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
+        Substs::fill_item(&mut substs, tcx, defs, &mut mk_kind);
         tcx.intern_substs(&substs)
     }
 
-    pub fn extend_to<FR, FT>(&self,
-                             tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                             def_id: DefId,
-                             mut mk_region: FR,
-                             mut mk_type: FT)
-                             -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
+    pub fn extend_to<F>(&self,
+                        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                        def_id: DefId,
+                        mut mk_kind: F)
+                        -> &'tcx Substs<'tcx>
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
     {
         let defs = tcx.generics_of(def_id);
         let mut result = Vec::with_capacity(defs.count());
         result.extend(self[..].iter().cloned());
-        Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type);
+        Substs::fill_single(&mut result, defs, &mut mk_kind);
         tcx.intern_substs(&result)
     }
 
-    pub fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+    pub fn fill_item<F>(substs: &mut Vec<Kind<'tcx>>,
                              tcx: TyCtxt<'a, 'gcx, 'tcx>,
                              defs: &ty::Generics,
-                             mk_region: &mut FR,
-                             mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+                             mk_kind: &mut F)
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+    {
 
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.generics_of(def_id);
-            Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
+            Substs::fill_item(substs, tcx, parent_defs, mk_kind);
         }
-        Substs::fill_single(substs, defs, mk_region, mk_type)
+        Substs::fill_single(substs, defs, mk_kind)
     }
 
-    fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+    fn fill_single<F>(substs: &mut Vec<Kind<'tcx>>,
                            defs: &ty::Generics,
-                           mk_region: &mut FR,
-                           mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
-        // Handle Self first, before all regions.
-        let mut types = defs.types.iter();
-        if defs.parent.is_none() && defs.has_self {
-            let def = types.next().unwrap();
-            let ty = mk_type(def, substs);
-            assert_eq!(def.index as usize, substs.len());
-            substs.push(ty.into());
-        }
-
-        for def in &defs.regions {
-            let region = mk_region(def, substs);
-            assert_eq!(def.index as usize, substs.len());
-            substs.push(Kind::from(region));
-        }
-
-        for def in types {
-            let ty = mk_type(def, substs);
-            assert_eq!(def.index as usize, substs.len());
-            substs.push(Kind::from(ty));
+                           mk_kind: &mut F)
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+    {
+        for param in &defs.params {
+            let kind = mk_kind(param, substs);
+            assert_eq!(param.index as usize, substs.len());
+            substs.push(kind);
         }
     }
 
@@ -308,13 +288,8 @@ pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
     }
 
     #[inline]
-    pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
-        self.type_at(ty_param_def.index as usize)
-    }
-
-    #[inline]
-    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region<'tcx> {
-        self.region_at(def.index as usize)
+    pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> {
+        self.type_at(def.index as usize).into()
     }
 
     /// Transform from substitutions for a child of `source_ancestor`
@@ -327,7 +302,7 @@ pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                        target_substs: &Substs<'tcx>)
                        -> &'tcx Substs<'tcx> {
         let defs = tcx.generics_of(source_ancestor);
-        tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
+        tcx.mk_substs(target_substs.iter().chain(&self[defs.params.len()..]).cloned())
     }
 
     pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics)
@@ -580,7 +555,7 @@ pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
         ty::TraitRef {
             def_id: trait_id,
-            substs: tcx.intern_substs(&substs[..defs.own_count()])
+            substs: tcx.intern_substs(&substs[..defs.params.len()])
         }
     }
 }
index 80dc3b2b452ce4047370fcf5683b9da55872d8fa..d5532f8f8355a3167ea79d8c40cb5db9a6f37255 100644 (file)
 use hir;
 use ich::NodeIdHashingMode;
 use middle::const_val::ConstVal;
-use traits;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use traits::{self, ObligationCause};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
 use ty::fold::TypeVisitor;
-use ty::subst::UnpackedKind;
+use ty::subst::{Substs, UnpackedKind};
 use ty::maps::TyCtxtAt;
 use ty::TypeVariants::*;
 use ty::layout::{Integer, IntegerExt};
 use util::common::ErrorReported;
 use middle::lang_items;
-use mir::interpret::{Value, PrimVal};
 
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
                                            HashStable};
@@ -167,9 +166,9 @@ fn disr_incr<'a, 'tcx>(
 }
 
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub enum CopyImplementationError<'tcx> {
-    InfrigingField(&'tcx ty::FieldDef),
+    InfrigingFields(Vec<&'tcx ty::FieldDef>),
     NotAnAdt,
     HasDestructor,
 }
@@ -192,7 +191,7 @@ pub enum Representability {
 impl<'tcx> ty::ParamEnv<'tcx> {
     pub fn can_type_implement_copy<'a>(self,
                                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       self_type: Ty<'tcx>, span: Span)
+                                       self_type: Ty<'tcx>)
                                        -> Result<(), CopyImplementationError<'tcx>> {
         // FIXME: (@jroesch) float this code up
         tcx.infer_ctxt().enter(|infcx| {
@@ -208,22 +207,29 @@ pub fn can_type_implement_copy<'a>(self,
                 _ => return Err(CopyImplementationError::NotAnAdt),
             };
 
-            let field_implements_copy = |field: &ty::FieldDef| {
-                let cause = traits::ObligationCause::dummy();
-                match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
-                    Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
-                    Err(..) => false,
-                }
-            };
-
+            let mut infringing = Vec::new();
             for variant in &adt.variants {
                 for field in &variant.fields {
-                    if !field_implements_copy(field) {
-                        return Err(CopyImplementationError::InfrigingField(field));
+                    let span = tcx.def_span(field.did);
+                    let ty = field.ty(tcx, substs);
+                    if ty.references_error() {
+                        continue;
                     }
+                    let cause = ObligationCause { span, ..ObligationCause::dummy() };
+                    let ctx = traits::FulfillmentContext::new();
+                    match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
+                        Ok(ty) => if infcx.type_moves_by_default(self, ty, span) {
+                            infringing.push(field);
+                        }
+                        Err(errors) => {
+                            infcx.report_fulfillment_errors(&errors, None, false);
+                        }
+                    };
                 }
             }
-
+            if !infringing.is_empty() {
+                return Err(CopyImplementationError::InfrigingFields(infringing));
+            }
             if adt.has_dtor(tcx) {
                 return Err(CopyImplementationError::HasDestructor);
             }
@@ -567,11 +573,14 @@ pub fn closure_env_ty(self,
 
     /// Given the def-id of some item that has no type parameters, make
     /// a suitable "empty substs" for it.
-    pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> {
-        ty::Substs::for_item(self, item_def_id,
-                             |_, _| self.types.re_erased,
-                             |_, _| {
-            bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+    pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
+        Substs::for_item(self, item_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => self.types.re_erased.into(),
+                GenericParamDefKind::Type(_) => {
+                    bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+                }
+            }
         })
     }
 
@@ -659,9 +668,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
             TyArray(_, n) => {
                 self.hash_discriminant_u8(&n.val);
                 match n.val {
-                    ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
+                    ConstVal::Value(alloc) => self.hash(alloc),
                     ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
-                    _ => bug!("arrays should not have {:?} as length", n)
                 }
             }
             TyRawPtr(m) => self.hash(m.mutbl),
index 4fb1017035168497b5d42b9534251e736a9e2e43..eaae874635f62772a1795aa4571a60445b62abad 100644 (file)
@@ -19,9 +19,8 @@
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon};
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
 use util::nodemap::FxHashSet;
-use mir::interpret::{Value, PrimVal};
 
 use std::cell::Cell;
 use std::fmt;
@@ -257,8 +256,10 @@ fn parameterized<F: fmt::Write>(&mut self,
         let verbose = self.is_verbose;
         let mut num_supplied_defaults = 0;
         let mut has_self = false;
-        let mut num_regions = 0;
-        let mut num_types = 0;
+        let mut own_counts = GenericParamCount {
+            lifetimes: 0,
+            types: 0,
+        };
         let mut is_value_path = false;
         let fn_trait_kind = ty::tls::with(|tcx| {
             // Unfortunately, some kinds of items (e.g., closures) don't have
@@ -304,6 +305,7 @@ fn parameterized<F: fmt::Write>(&mut self,
                 }
             }
             let mut generics = tcx.generics_of(item_def_id);
+            let child_own_counts = generics.own_counts();
             let mut path_def_id = did;
             has_self = generics.has_self;
 
@@ -311,10 +313,9 @@ fn parameterized<F: fmt::Write>(&mut self,
             if let Some(def_id) = generics.parent {
                 // Methods.
                 assert!(is_value_path);
-                child_types = generics.types.len();
+                child_types = child_own_counts.types;
                 generics = tcx.generics_of(def_id);
-                num_regions = generics.regions.len();
-                num_types = generics.types.len();
+                own_counts = generics.own_counts();
 
                 if has_self {
                     print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?;
@@ -329,20 +330,30 @@ fn parameterized<F: fmt::Write>(&mut self,
                     assert_eq!(has_self, false);
                 } else {
                     // Types and traits.
-                    num_regions = generics.regions.len();
-                    num_types = generics.types.len();
+                    own_counts = child_own_counts;
                 }
             }
 
             if !verbose {
-                if generics.types.last().map_or(false, |def| def.has_default) {
+                let mut type_params =
+                    generics.params.iter().rev().filter_map(|param| {
+                        match param.kind {
+                            GenericParamDefKind::Type(ty) => Some((param.def_id, ty.has_default)),
+                            GenericParamDefKind::Lifetime => None,
+                        }
+                    }).peekable();
+                let has_default = {
+                    let has_default = type_params.peek().map(|(_, has_default)| has_default);
+                    *has_default.unwrap_or(&false)
+                };
+                if has_default {
                     if let Some(substs) = tcx.lift(&substs) {
-                        let tps = substs.types().rev().skip(child_types);
-                        for (def, actual) in generics.types.iter().rev().zip(tps) {
-                            if !def.has_default {
+                        let mut types = substs.types().rev().skip(child_types);
+                        for ((def_id, has_default), actual) in type_params.zip(types) {
+                            if !has_default {
                                 break;
                             }
-                            if tcx.type_of(def.def_id).subst(tcx, substs) != actual {
+                            if tcx.type_of(def_id).subst(tcx, substs) != actual {
                                 break;
                             }
                             num_supplied_defaults += 1;
@@ -402,10 +413,11 @@ fn parameterized<F: fmt::Write>(&mut self,
             Ok(())
         };
 
-        print_regions(f, "<", 0, num_regions)?;
+        print_regions(f, "<", 0, own_counts.lifetimes)?;
 
-        let tps = substs.types().take(num_types - num_supplied_defaults)
-                                .skip(has_self as usize);
+        let tps = substs.types()
+                        .take(own_counts.types - num_supplied_defaults)
+                        .skip(has_self as usize);
 
         for ty in tps {
             start_or_continue(f, "<", ", ")?;
@@ -436,10 +448,10 @@ fn parameterized<F: fmt::Write>(&mut self,
                 write!(f, "::{}", item_name)?;
             }
 
-            print_regions(f, "::<", num_regions, usize::MAX)?;
+            print_regions(f, "::<", own_counts.lifetimes, usize::MAX)?;
 
             // FIXME: consider being smart with defaults here too
-            for ty in substs.types().skip(num_types) {
+            for ty in substs.types().skip(own_counts.types) {
                 start_or_continue(f, "::<", ", ")?;
                 ty.print_display(f, self)?;
             }
@@ -589,18 +601,14 @@ fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result
     }
 }
 
-impl fmt::Debug for ty::TypeParameterDef {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeParameterDef({}, {:?}, {})",
-               self.name,
-               self.def_id,
-               self.index)
-    }
-}
-
-impl fmt::Debug for ty::RegionParameterDef {
+impl fmt::Debug for ty::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "RegionParameterDef({}, {:?}, {})",
+        let type_name = match self.kind {
+            ty::GenericParamDefKind::Lifetime => "Lifetime",
+            ty::GenericParamDefKind::Type(_) => "Type",
+        };
+        write!(f, "{}({}, {:?}, {})",
+               type_name,
                self.name,
                self.def_id,
                self.index)
@@ -1183,15 +1191,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 TyArray(ty, sz) => {
                     print!(f, cx, write("["), print(ty), write("; "))?;
                     match sz.val {
-                        ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
-                            write!(f, "{}", sz)?;
-                        }
+                        ConstVal::Value(..) => ty::tls::with(|tcx| {
+                            write!(f, "{}", sz.unwrap_usize(tcx))
+                        })?,
                         ConstVal::Unevaluated(_def_id, _substs) => {
                             write!(f, "_")?;
                         }
-                        _ => {
-                            write!(f, "{:?}", sz)?;
-                        }
                     }
                     write!(f, "]")
                 }
index 9178d0d00faa49ae0c34f68e9d2a214b32ae047c..6f1cbcad2f46c3bec9f83df0dd1614a4548d612c 100644 (file)
@@ -16,6 +16,7 @@ serialize = { path = "../libserialize" }
 cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
 parking_lot_core = "0.2.8"
+rustc-rayon = "0.1.0"
 
 [dependencies.parking_lot]
 version = "0.5"
index dc487f1162ca9d074b8735937e069b846a7dbc60..54407658e6ccc85f77e27682800529d98db3fba0 100644 (file)
@@ -175,7 +175,7 @@ pub fn children(&self, node: Node) -> &[Node] {
 }
 
 impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&DominatorTreeNode {
                             tree: self,
                             node: self.root,
@@ -190,7 +190,7 @@ struct DominatorTreeNode<'tree, Node: Idx> {
 }
 
 impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let subtrees: Vec<_> = self.tree
             .children(self.node)
             .iter()
index 597d1627ada03da578556f761897937181a063c7..b2e7450e76cdf4a9063e4dbb9e5bf6c147d9165d 100644 (file)
@@ -44,6 +44,7 @@
 #[macro_use]
 extern crate cfg_if;
 extern crate stable_deref_trait;
+extern crate rustc_rayon as rayon;
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
 #[allow(unused_extern_crates)]
index c466b8f8ad1b5acb716db8b2720dd2cadb25c08f..aa113fac9fb7dff28baa92dfba7bfe5f0b80b50b 100644 (file)
@@ -1002,7 +1002,7 @@ impl<O, T: ?Sized> Debug for OwningRef<O, T>
     where O: Debug,
           T: Debug,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f,
                "OwningRef {{ owner: {:?}, reference: {:?} }}",
                self.owner(),
@@ -1014,7 +1014,7 @@ impl<O, T: ?Sized> Debug for OwningRefMut<O, T>
     where O: Debug,
           T: Debug,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f,
                "OwningRefMut {{ owner: {:?}, reference: {:?} }}",
                self.owner(),
@@ -1047,7 +1047,7 @@ unsafe impl<O, T: ?Sized> Sync for OwningRefMut<O, T>
     where O: Sync, for<'a> (&'a mut T): Sync {}
 
 impl Debug for Erased {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "<Erased>",)
     }
 }
index 3b7d6efbdae1e760694fced946ac9031bd2db2ec..3661763133014b593f42fd30f0bc1bbd345f3c44 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
+//! This module defines types which are thread safe if cfg!(parallel_queries) is true.
 //!
 //! `Lrc` is an alias of either Rc or Arc.
 //!
 use std::ops::{Deref, DerefMut};
 use owning_ref::{Erased, OwningRef};
 
+pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+    where A: FnOnce() -> RA,
+          B: FnOnce() -> RB
+{
+    (oper_a(), oper_b())
+}
+
+pub struct SerialScope;
+
+impl SerialScope {
+    pub fn spawn<F>(&self, f: F)
+        where F: FnOnce(&SerialScope)
+    {
+        f(self)
+    }
+}
+
+pub fn serial_scope<F, R>(f: F) -> R
+    where F: FnOnce(&SerialScope) -> R
+{
+    f(&SerialScope)
+}
+
 cfg_if! {
     if #[cfg(not(parallel_queries))] {
         pub auto trait Send {}
@@ -55,9 +78,19 @@ macro_rules! rustc_erase_owner {
             }
         }
 
+        pub use self::serial_join as join;
+        pub use self::serial_scope as scope;
+
+        pub use std::iter::Iterator as ParallelIterator;
+
+        pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
+            t.into_iter()
+        }
+
         pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;
 
         pub use std::rc::Rc as Lrc;
+        pub use std::rc::Weak as Weak;
         pub use std::cell::Ref as ReadGuard;
         pub use std::cell::RefMut as WriteGuard;
         pub use std::cell::RefMut as LockGuard;
@@ -160,6 +193,7 @@ pub fn take(&self) -> Option<T> {
         pub use parking_lot::MutexGuard as LockGuard;
 
         pub use std::sync::Arc as Lrc;
+        pub use std::sync::Weak as Weak;
 
         pub use self::Lock as MTLock;
 
@@ -167,6 +201,14 @@ pub fn take(&self) -> Option<T> {
         use parking_lot::RwLock as InnerRwLock;
 
         use std::thread;
+        pub use rayon::{join, scope};
+
+        pub use rayon::iter::ParallelIterator;
+        use rayon::iter::IntoParallelIterator;
+
+        pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
+            t.into_par_iter()
+        }
 
         pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;
 
index 5aae1bcad896f18fdee8a2d9ac60f8e7d27ab865..1827533f0acb5977be80b10f24c89e85f7291980 100644 (file)
@@ -13,6 +13,8 @@ arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
 env_logger = { version = "0.5", default-features = false }
+rustc-rayon = "0.1.0"
+scoped-tls = { version = "0.1.1", features = ["nightly"] }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_target = { path = "../librustc_target" }
index 2fb811eba1e9a197eb6ec0cae4edb099b0a74723..62b3accc46f18e6bfc85600df45e1def21ef59c2 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::session::search_paths::PathKind;
 use rustc::lint;
 use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
 use rustc::traits;
@@ -49,7 +49,7 @@
 use std::io::{self, Write};
 use std::iter;
 use std::path::{Path, PathBuf};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
 use std::sync::mpsc;
 use syntax::{self, ast, attr, diagnostics, visit};
 use syntax::ext::base::ExtCtxt;
 
 use profile;
 
+#[cfg(not(parallel_queries))]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+    opts: config::Options,
+    f: F
+) -> R {
+    f(opts)
+}
+
+#[cfg(parallel_queries)]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+    opts: config::Options,
+    f: F
+) -> R {
+    use syntax;
+    use syntax_pos;
+    use rayon::{ThreadPoolBuilder, ThreadPool};
+
+    let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts))
+                                         .stack_size(16 * 1024 * 1024);
+
+    let with_pool = move |pool: &ThreadPool| {
+        pool.install(move || f(opts))
+    };
+
+    syntax::GLOBALS.with(|syntax_globals| {
+        syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+            // The main handler run for each Rayon worker thread and sets up
+            // the thread local rustc uses. syntax_globals and syntax_pos_globals are
+            // captured and set on the new threads. ty::tls::with_thread_locals sets up
+            // thread local callbacks from libsyntax
+            let main_handler = move |worker: &mut FnMut()| {
+                syntax::GLOBALS.set(syntax_globals, || {
+                    syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+                        ty::tls::with_thread_locals(|| {
+                            worker()
+                        })
+                    })
+                })
+            };
+
+            ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+        })
+    })
+}
+
 pub fn compile_input(
     trans: Box<TransCrate>,
     sess: &Session,
@@ -980,15 +1025,16 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(
     let dep_graph = match future_dep_graph {
         None => DepGraph::new_disabled(),
         Some(future) => {
-            let prev_graph = time(sess, "blocked while dep-graph loading finishes", || {
-                future
-                    .open()
-                    .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
-                        message: format!("could not decode incremental cache: {:?}", e),
-                    })
-                    .open(sess)
-            });
-            DepGraph::new(prev_graph)
+            let (prev_graph, prev_work_products) =
+                time(sess, "blocked while dep-graph loading finishes", || {
+                    future
+                        .open()
+                        .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
+                            message: format!("could not decode incremental cache: {:?}", e),
+                        })
+                        .open(sess)
+                });
+            DepGraph::new(prev_graph, prev_work_products)
         }
     };
     let hir_forest = time(sess, "lowering ast -> hir", || {
@@ -1046,7 +1092,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(
     trans: &TransCrate,
     control: &CompileController,
     sess: &'tcx Session,
-    cstore: &'tcx CrateStore,
+    cstore: &'tcx CrateStoreDyn,
     hir_map: hir_map::Map<'tcx>,
     mut analysis: ty::CrateAnalysis,
     resolutions: Resolutions,
index a1052ca6c3ca9520fc7cf8f4e38ebc106f8263a7..148fbd73e9bd8ffc7d1e9cafea1c8cf684c0b684 100644 (file)
 #![feature(rustc_stack_internals)]
 #![feature(no_debug)]
 
+#![recursion_limit="256"]
+
 extern crate arena;
 extern crate getopts;
 extern crate graphviz;
 extern crate env_logger;
 #[cfg(unix)]
 extern crate libc;
+extern crate rustc_rayon as rayon;
 extern crate rustc;
 extern crate rustc_allocator;
 extern crate rustc_target;
@@ -51,6 +54,7 @@
 extern crate rustc_traits;
 extern crate rustc_trans_utils;
 extern crate rustc_typeck;
+extern crate scoped_tls;
 extern crate serialize;
 #[macro_use]
 extern crate log;
@@ -64,7 +68,7 @@
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
 use rustc_data_structures::OnDrop;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::CompileIncomplete;
@@ -448,22 +452,33 @@ fn GetModuleFileNameW(hModule: usize,
 // See comments on CompilerCalls below for details about the callbacks argument.
 // The FileLoader provides a way to load files from sources other than the file system.
 pub fn run_compiler<'a>(args: &[String],
-                        callbacks: &mut CompilerCalls<'a>,
+                        callbacks: &mut (CompilerCalls<'a> + sync::Send),
                         file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
                         emitter_dest: Option<Box<Write + Send>>)
                         -> (CompileResult, Option<Session>)
 {
     syntax::with_globals(|| {
-        run_compiler_impl(args, callbacks, file_loader, emitter_dest)
+        let matches = match handle_options(args) {
+            Some(matches) => matches,
+            None => return (Ok(()), None),
+        };
+
+        let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+
+        driver::spawn_thread_pool(sopts, |sopts| {
+            run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
+        })
     })
 }
 
-fn run_compiler_impl<'a>(args: &[String],
-                         callbacks: &mut CompilerCalls<'a>,
-                         file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
-                         emitter_dest: Option<Box<Write + Send>>)
-                         -> (CompileResult, Option<Session>)
-{
+fn run_compiler_with_pool<'a>(
+    matches: getopts::Matches,
+    sopts: config::Options,
+    cfg: ast::CrateConfig,
+    callbacks: &mut (CompilerCalls<'a> + sync::Send),
+    file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
+    emitter_dest: Option<Box<Write + Send>>
+) -> (CompileResult, Option<Session>) {
     macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         match $expr {
             Compilation::Stop => return (Ok(()), $sess),
@@ -471,13 +486,6 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         }
     }}
 
-    let matches = match handle_options(args) {
-        Some(matches) => matches,
-        None => return (Ok(()), None),
-    };
-
-    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
-
     let descriptions = diagnostics_registry();
 
     do_or_return!(callbacks.early_callback(&matches,
index 70b73ebb8cdeb476f5b978bdf9579a8e017542a7..108b47623383c0e3e27755fca3c4dd01f4bbd1d0 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
 use rustc::cfg;
 use rustc::cfg::graphviz::LabelledCFG;
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
 use rustc::session::Session;
 use rustc::session::config::{Input, OutputFilenames};
 use rustc_borrowck as borrowck;
@@ -199,7 +199,7 @@ fn call_with_pp_support<'tcx, A, F>(&self,
     }
     fn call_with_pp_support_hir<'tcx, A, F>(&self,
                                                sess: &'tcx Session,
-                                               cstore: &'tcx CrateStore,
+                                               cstore: &'tcx CrateStoreDyn,
                                                hir_map: &hir_map::Map<'tcx>,
                                                analysis: &ty::CrateAnalysis,
                                                resolutions: &Resolutions,
@@ -912,7 +912,7 @@ pub fn print_after_parsing(sess: &Session,
 }
 
 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                                cstore: &'tcx CrateStore,
+                                                cstore: &'tcx CrateStoreDyn,
                                                 hir_map: &hir_map::Map<'tcx>,
                                                 analysis: &ty::CrateAnalysis,
                                                 resolutions: &Resolutions,
@@ -1068,7 +1068,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 // with a different callback than the standard driver, so that isn't easy.
 // Instead, we call that function ourselves.
 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                       cstore: &'a CrateStore,
+                                       cstore: &'a CrateStoreDyn,
                                        hir_map: &hir_map::Map<'tcx>,
                                        analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
index d2ee3d8743c2cd74886d8e3b3a5d18098c5d22e7..78c95a5ce0504e1a60a19433bdc4db3395fe9c60 100644 (file)
@@ -99,20 +99,25 @@ fn test_env<F>(source_string: &str,
     where F: FnOnce(Env)
 {
     syntax::with_globals(|| {
-        test_env_impl(source_string, args, body)
+        let mut options = config::basic_options();
+        options.debugging_opts.verbose = true;
+        options.unstable_features = UnstableFeatures::Allow;
+
+        driver::spawn_thread_pool(options, |options| {
+            test_env_with_pool(options, source_string, args, body)
+        })
     });
 }
 
-fn test_env_impl<F>(source_string: &str,
-                    (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
-                    body: F)
+fn test_env_with_pool<F>(
+    options: config::Options,
+    source_string: &str,
+    (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
+    body: F
+)
     where F: FnOnce(Env)
 {
-    let mut options = config::basic_options();
-    options.debugging_opts.verbose = true;
-    options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
-
     let sess = session::build_session_(options,
                                        None,
                                        diagnostic_handler,
@@ -303,7 +308,7 @@ pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
 
     pub fn t_param(&self, index: u32) -> Ty<'tcx> {
         let name = format!("T{}", index);
-        self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_interned_str())
+        self.infcx.tcx.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
     }
 
     pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
index c2b442e949758a19c64f4b2aa73dc8d7264f6282..fd90e1cbe0866b16bdbfaefb2dfd20c4e6055a20 100644 (file)
@@ -232,7 +232,7 @@ pub fn raise(self) -> ! {
 }
 
 impl fmt::Display for FatalError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "parser fatal error")
     }
 }
@@ -249,7 +249,7 @@ fn description(&self) -> &str {
 pub struct ExplicitBug;
 
 impl fmt::Display for ExplicitBug {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "parser internal bug")
     }
 }
index a5e07bcec24bb65c242de5765c68c6ad9c3792a9..ababce69e3170d850e939df33dfefdc3b4039ad6 100644 (file)
@@ -36,9 +36,9 @@
 pub use persist::load_dep_graph;
 pub use persist::load_query_result_cache;
 pub use persist::LoadResult;
+pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
 pub use persist::save_dep_graph;
-pub use persist::save_trans_partition;
-pub use persist::save_work_products;
+pub use persist::save_work_product_index;
 pub use persist::in_incr_comp_dir;
 pub use persist::prepare_session_directory;
 pub use persist::finalize_session_directory;
index 44d6e532f79bb4aa67b52c4446ac18dc665d4aef..f846759545eb949fbf82cf122be625c2325b7cad 100644 (file)
@@ -10,7 +10,8 @@
 
 //! Code to save/load the dep-graph from files.
 
-use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
+use rustc_data_structures::fx::FxHashMap;
+use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc::ty::maps::OnDiskCache;
@@ -32,65 +33,22 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     tcx.allocate_metadata_dep_nodes();
     tcx.precompute_in_scope_traits_hashes();
-
-    if tcx.sess.incr_comp_session_dir_opt().is_none() {
-        // If we are only building with -Zquery-dep-graph but without an actual
-        // incr. comp. session directory, we exit here. Otherwise we'd fail
-        // when trying to load work products.
-        return
-    }
-
-    let work_products_path = work_products_path(tcx.sess);
-    let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path);
-
-    if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
-        // Decode the list of work_products
-        let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
-        let work_products: Vec<SerializedWorkProduct> =
-            RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
-                let msg = format!("Error decoding `work-products` from incremental \
-                                   compilation session directory: {}", e);
-                tcx.sess.fatal(&msg[..])
-            });
-
-        for swp in work_products {
-            let mut all_files_exist = true;
-            for &(_, ref file_name) in swp.work_product.saved_files.iter() {
-                let path = in_incr_comp_dir_sess(tcx.sess, file_name);
-                if !path.exists() {
-                    all_files_exist = false;
-
-                    if tcx.sess.opts.debugging_opts.incremental_info {
-                        eprintln!("incremental: could not find file for work \
-                                   product: {}", path.display());
-                    }
-                }
-            }
-
-            if all_files_exist {
-                debug!("reconcile_work_products: all files for {:?} exist", swp);
-                tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product);
-            } else {
-                debug!("reconcile_work_products: some file for {:?} does not exist", swp);
-                delete_dirty_work_product(tcx, swp);
-            }
-        }
-    }
 }
 
+type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
+
 pub enum LoadResult<T> {
     Ok { data: T },
     DataOutOfDate,
     Error { message: String },
 }
 
-
-impl LoadResult<PreviousDepGraph> {
-    pub fn open(self, sess: &Session) -> PreviousDepGraph {
+impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
+    pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
         match self {
             LoadResult::Error { message } => {
                 sess.warn(&message);
-                PreviousDepGraph::new(SerializedDepGraph::new())
+                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
             },
             LoadResult::DataOutOfDate => {
                 if let Err(err) = delete_all_session_dir_contents(sess) {
@@ -98,7 +56,7 @@ pub fn open(self, sess: &Session) -> PreviousDepGraph {
                                       incremental compilation session directory contents `{}`: {}.",
                                       dep_graph_path(sess).display(), err));
                 }
-                PreviousDepGraph::new(SerializedDepGraph::new())
+                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
             }
             LoadResult::Ok { data } => data
         }
@@ -125,10 +83,10 @@ fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>,
     }
 }
 
-fn delete_dirty_work_product(tcx: TyCtxt,
+fn delete_dirty_work_product(sess: &Session,
                              swp: SerializedWorkProduct) {
     debug!("delete_dirty_work_product({:?})", swp);
-    work_product::delete_workproduct_files(tcx.sess, &swp.work_product);
+    work_product::delete_workproduct_files(sess, &swp.work_product);
 }
 
 /// Either a result that has already be computed or a
@@ -149,7 +107,7 @@ pub fn open(self) -> std::thread::Result<T> {
 
 /// Launch a thread and load the dependency graph in the background.
 pub fn load_dep_graph(sess: &Session) ->
-    MaybeAsync<LoadResult<PreviousDepGraph>>
+    MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
 {
     // Since `sess` isn't `Sync`, we perform all accesses to `sess`
     // before we fire the background thread.
@@ -159,7 +117,7 @@ pub fn load_dep_graph(sess: &Session) ->
     if sess.opts.incremental.is_none() {
         // No incremental compilation.
         return MaybeAsync::Sync(LoadResult::Ok {
-            data: PreviousDepGraph::new(SerializedDepGraph::new())
+            data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
         });
     }
 
@@ -169,6 +127,50 @@ pub fn load_dep_graph(sess: &Session) ->
     let report_incremental_info = sess.opts.debugging_opts.incremental_info;
     let expected_hash = sess.opts.dep_tracking_hash();
 
+    let mut prev_work_products = FxHashMap();
+
+    // If we are only building with -Zquery-dep-graph but without an actual
+    // incr. comp. session directory, we skip this. Otherwise we'd fail
+    // when trying to load work products.
+    if sess.incr_comp_session_dir_opt().is_some() {
+        let work_products_path = work_products_path(sess);
+        let load_result = load_data(report_incremental_info, &work_products_path);
+
+        if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
+            // Decode the list of work_products
+            let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
+            let work_products: Vec<SerializedWorkProduct> =
+                RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
+                    let msg = format!("Error decoding `work-products` from incremental \
+                                    compilation session directory: {}", e);
+                    sess.fatal(&msg[..])
+                });
+
+            for swp in work_products {
+                let mut all_files_exist = true;
+                for &(_, ref file_name) in swp.work_product.saved_files.iter() {
+                    let path = in_incr_comp_dir_sess(sess, file_name);
+                    if !path.exists() {
+                        all_files_exist = false;
+
+                        if sess.opts.debugging_opts.incremental_info {
+                            eprintln!("incremental: could not find file for work \
+                                    product: {}", path.display());
+                        }
+                    }
+                }
+
+                if all_files_exist {
+                    debug!("reconcile_work_products: all files for {:?} exist", swp);
+                    prev_work_products.insert(swp.id, swp.work_product);
+                } else {
+                    debug!("reconcile_work_products: some file for {:?} does not exist", swp);
+                    delete_dirty_work_product(sess, swp);
+                }
+            }
+        }
+    }
+
     MaybeAsync::Async(std::thread::spawn(move || {
         time_ext(time_passes, None, "background load prev dep-graph", move || {
             match load_data(report_incremental_info, &path) {
@@ -195,7 +197,7 @@ pub fn load_dep_graph(sess: &Session) ->
                     let dep_graph = SerializedDepGraph::decode(&mut decoder)
                         .expect("Error reading cached dep-graph");
 
-                    LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) }
+                    LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
                 }
             }
         })
index 755a550b5bca31e4af3a120cd56d4b6ce22dd204..e1f00db56d5cbc0572214a3a15d94941e7a8b09e 100644 (file)
@@ -29,6 +29,6 @@
 pub use self::load::load_query_result_cache;
 pub use self::load::LoadResult;
 pub use self::save::save_dep_graph;
-pub use self::save::save_work_products;
-pub use self::work_product::save_trans_partition;
+pub use self::save::save_work_product_index;
+pub use self::work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
 pub use self::work_product::delete_workproduct_files;
index e524fcecf9094a3edce0a932d97ee83f2878272c..be725b17933215661af70724ba01e6b4c432a7b7 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::dep_graph::{DepGraph, DepKind};
+use rustc::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc::util::common::time;
@@ -55,22 +55,22 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     })
 }
 
-pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
+pub fn save_work_product_index(sess: &Session,
+                               dep_graph: &DepGraph,
+                               new_work_products: FxHashMap<WorkProductId, WorkProduct>) {
     if sess.opts.incremental.is_none() {
         return;
     }
 
-    debug!("save_work_products()");
+    debug!("save_work_product_index()");
     dep_graph.assert_ignored();
     let path = work_products_path(sess);
-    save_in(sess, path, |e| encode_work_products(dep_graph, e));
+    save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
     // content, they are just not needed anymore.
-    let new_work_products = dep_graph.work_products();
     let previous_work_products = dep_graph.previous_work_products();
-
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
             work_product::delete_workproduct_files(sess, wp);
@@ -234,10 +234,9 @@ struct Stat {
     Ok(())
 }
 
-fn encode_work_products(dep_graph: &DepGraph,
-                        encoder: &mut Encoder) -> io::Result<()> {
-    let work_products: Vec<_> = dep_graph
-        .work_products()
+fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduct>,
+                             encoder: &mut Encoder) -> io::Result<()> {
+    let serialized_products: Vec<_> = work_products
         .iter()
         .map(|(id, work_product)| {
             SerializedWorkProduct {
@@ -247,7 +246,7 @@ fn encode_work_products(dep_graph: &DepGraph,
         })
         .collect();
 
-    work_products.encode(encoder)
+    serialized_products.encode(encoder)
 }
 
 fn encode_query_cache(tcx: TyCtxt,
index 879132bcacfcfcd86a3c6426152e7fc95d016e75..d0c7766cbae08bd3338ba2db91baa965c359ec1a 100644 (file)
 //! This module contains files for saving intermediate work-products.
 
 use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
 use rustc::session::Session;
 use rustc::util::fs::link_or_copy;
 use std::path::PathBuf;
 use std::fs as std_fs;
 
-pub fn save_trans_partition(sess: &Session,
-                            dep_graph: &DepGraph,
-                            cgu_name: &str,
-                            files: &[(WorkProductFileKind, PathBuf)]) {
-    debug!("save_trans_partition({:?},{:?})",
+pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
+    sess: &Session,
+    cgu_name: &str,
+    files: &[(WorkProductFileKind, PathBuf)]
+) -> Option<(WorkProductId, WorkProduct)> {
+    debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})",
            cgu_name,
            files);
     if sess.opts.incremental.is_none() {
-        return
+        return None
     }
     let work_product_id = WorkProductId::from_cgu_name(cgu_name);
 
@@ -53,8 +54,8 @@ pub fn save_trans_partition(sess: &Session,
              })
              .collect();
     let saved_files = match saved_files {
+        None => return None,
         Some(v) => v,
-        None => return,
     };
 
     let work_product = WorkProduct {
@@ -62,7 +63,7 @@ pub fn save_trans_partition(sess: &Session,
         saved_files,
     };
 
-    dep_graph.insert_work_product(&work_product_id, work_product);
+    Some((work_product_id, work_product))
 }
 
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
index 5102bfe766eeff2370e63610b3043b9fa2357797..0b1e9081a725e6696f04bd967ad4d1fa080336f1 100644 (file)
@@ -541,7 +541,7 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         if !ty.moves_by_default(cx.tcx, param_env, item.span) {
             return;
         }
-        if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() {
+        if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
             cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
                          item.span,
                          "type could implement `Copy`; consider adding `impl \
@@ -1287,32 +1287,27 @@ fn get_lints(&self) -> LintArray {
 
 impl UnreachablePub {
     fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
-                    vis: &hir::Visibility, span: Span, exportable: bool) {
+                    vis: &hir::Visibility, span: Span, exportable: bool,
+                    mut applicability: Applicability) {
         if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public {
+            if span.ctxt().outer().expn_info().is_some() {
+                applicability = Applicability::MaybeIncorrect;
+            }
             let def_span = cx.tcx.sess.codemap().def_span(span);
             let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
                                               &format!("unreachable `pub` {}", what));
-            // visibility is token at start of declaration (can be macro
-            // variable rather than literal `pub`)
+            // We are presuming that visibility is token at start of
+            // declaration (can be macro variable rather than literal `pub`)
             let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' ');
             let replacement = if cx.tcx.features().crate_visibility_modifier {
                 "crate"
             } else {
                 "pub(crate)"
             }.to_owned();
-            let app = if span.ctxt().outer().expn_info().is_none() {
-                // even if macros aren't involved the suggestion
-                // may be incorrect -- the user may have mistakenly
-                // hidden it behind a private module and this lint is
-                // a helpful way to catch that. However, we're trying
-                // not to change the nature of the code with this lint
-                // so it's marked as machine applicable.
-                Applicability::MachineApplicable
-            } else {
-                Applicability::MaybeIncorrect
-            };
-            err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility",
-                                                   replacement, app);
+            err.span_suggestion_with_applicability(pub_span,
+                                                   "consider restricting its visibility",
+                                                   replacement,
+                                                   applicability);
             if exportable {
                 err.help("or consider exporting it for use by other crates");
             }
@@ -1321,21 +1316,31 @@ fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
     }
 }
 
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
-        self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+        let applicability = match item.node {
+            // suggestion span-manipulation is inadequate for `pub use
+            // module::{item}` (Issue #50455)
+            hir::ItemUse(..) => Applicability::MaybeIncorrect,
+            _ => Applicability::MachineApplicable,
+        };
+        self.perform_lint(cx, "item", item.id, &item.vis, item.span, true, applicability);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) {
-        self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true);
+        self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis,
+                          foreign_item.span, true, Applicability::MachineApplicable);
     }
 
     fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
-        self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+        self.perform_lint(cx, "field", field.id, &field.vis, field.span, false,
+                          Applicability::MachineApplicable);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
-        self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+        self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false,
+                          Applicability::MachineApplicable);
     }
 }
 
@@ -1543,6 +1548,9 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+        if !cx.tcx.features().extern_absolute_paths {
+            return
+        }
         if let hir::ItemExternCrate(ref orig) =  it.node {
             if it.attrs.iter().any(|a| a.check_name("macro_use")) {
                 return
@@ -1560,10 +1568,10 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
 
                 if let Some(orig) = orig {
                     err.span_suggestion(it.span, &help,
-                        format!("{}use {} as {}", pub_, orig, it.name));
+                        format!("{}use {} as {};", pub_, orig, it.name));
                 } else {
                     err.span_suggestion(it.span, &help,
-                        format!("{}use {}", pub_, it.name));
+                        format!("{}use {};", pub_, it.name));
                 }
             } else {
                 err.span_suggestion(it.span, "remove it", "".into());
@@ -1583,3 +1591,61 @@ fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod,
         self.0 += 1;
     }
 }
+
+/// Lint for trait and lifetime bounds that don't depend on type parameters
+/// which either do nothing, or stop the item from being used.
+pub struct TrivialConstraints;
+
+declare_lint! {
+    TRIVIAL_BOUNDS,
+    Warn,
+    "these bounds don't depend on an type parameters"
+}
+
+impl LintPass for TrivialConstraints {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TRIVIAL_BOUNDS)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
+    fn check_item(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        item: &'tcx hir::Item,
+    ) {
+        use rustc::ty::fold::TypeFoldable;
+        use rustc::ty::Predicate::*;
+
+
+        if cx.tcx.features().trivial_bounds {
+            let def_id = cx.tcx.hir.local_def_id(item.id);
+            let predicates = cx.tcx.predicates_of(def_id);
+            for predicate in &predicates.predicates {
+                let predicate_kind_name = match *predicate {
+                    Trait(..) => "Trait",
+                    TypeOutlives(..) |
+                    RegionOutlives(..) => "Lifetime",
+
+                    // Ignore projections, as they can only be global
+                    // if the trait bound is global
+                    Projection(..) |
+                    // Ignore bounds that a user can't type
+                    WellFormed(..) |
+                    ObjectSafe(..) |
+                    ClosureKind(..) |
+                    Subtype(..) |
+                    ConstEvaluatable(..) => continue,
+                };
+                if predicate.is_global() {
+                    cx.span_lint(
+                        TRIVIAL_BOUNDS,
+                        item.span,
+                        &format!("{} bound {} does not depend on any type \
+                                or lifetime parameters", predicate_kind_name, predicate),
+                    );
+                }
+            }
+        }
+    }
+}
index 4403e1e3358b288bc174d42211a887d1cc112da4..ae44ea6b65b9ac596f6b39a8dee13be8a8e7b87b 100644 (file)
@@ -137,6 +137,7 @@ macro_rules! add_lint_group {
                  UnreachablePub,
                  TypeAliasBounds,
                  UnusedBrokenConst,
+                 TrivialConstraints,
                  );
 
     add_builtin_with_new!(sess,
@@ -179,7 +180,7 @@ macro_rules! add_lint_group {
                     UNUSED_PARENS);
 
     add_lint_group!(sess,
-                    "rust_2018_migration",
+                    "rust_2018_idioms",
                     BARE_TRAIT_OBJECT,
                     UNREACHABLE_PUB,
                     UNNECESSARY_EXTERN_CRATE);
index dba2e918f6f3a10a3fb44618bfcd55d6909de825..c1e32c7c0226ed94898566f5e3423e9579563392 100644 (file)
@@ -1651,6 +1651,7 @@ pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef,
                                                MergeFunctions: bool,
                                                SLPVectorize: bool,
                                                LoopVectorize: bool,
+                                               PrepareForThinLTO: bool,
                                                PGOGenPath: *const c_char,
                                                PGOUsePath: *const c_char);
     pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
index d0237071a6058d14cb3731e12771bd4c9b93b294..87b3a2dc69ff91fc5f3bc4f5bb9b98ff7ecbb45d 100644 (file)
@@ -51,7 +51,6 @@ pub struct Library {
 pub struct CrateLoader<'a> {
     pub sess: &'a Session,
     cstore: &'a CStore,
-    next_crate_num: CrateNum,
     local_crate_name: Symbol,
 }
 
@@ -102,7 +101,6 @@ pub fn new(sess: &'a Session, cstore: &'a CStore, local_crate_name: &str) -> Sel
         CrateLoader {
             sess,
             cstore,
-            next_crate_num: cstore.next_crate_num(),
             local_crate_name: Symbol::intern(local_crate_name),
         }
     }
@@ -198,8 +196,7 @@ fn register_crate(&mut self,
         self.verify_no_symbol_conflicts(span, &crate_root);
 
         // Claim this crate number and cache it
-        let cnum = self.next_crate_num;
-        self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1);
+        let cnum = self.cstore.alloc_new_crate_num();
 
         // Stash paths for top-most crate locally if necessary.
         let crate_paths = if root.is_none() {
@@ -219,6 +216,8 @@ fn register_crate(&mut self,
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
+        let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
+
         let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
             crate_root.def_path_table.decode((&metadata, self.sess))
         });
@@ -239,8 +238,9 @@ fn register_crate(&mut self,
             }),
             root: crate_root,
             blob: metadata,
-            cnum_map: Lock::new(cnum_map),
+            cnum_map,
             cnum,
+            dependencies: Lock::new(dependencies),
             codemap_import_info: RwLock::new(vec![]),
             attribute_cache: Lock::new([Vec::new(), Vec::new()]),
             dep_kind: Lock::new(dep_kind),
@@ -392,7 +392,7 @@ fn update_extern_crate(&mut self,
 
         // Propagate the extern crate info to dependencies.
         extern_crate.direct = false;
-        for &dep_cnum in cmeta.cnum_map.borrow().iter() {
+        for &dep_cnum in cmeta.dependencies.borrow().iter() {
             self.update_extern_crate(dep_cnum, extern_crate, visited);
         }
     }
@@ -1040,7 +1040,7 @@ fn inject_dependency_if(&self,
             }
 
             info!("injecting a dep from {} to {}", cnum, krate);
-            data.cnum_map.borrow_mut().push(krate);
+            data.dependencies.borrow_mut().push(krate);
         });
     }
 }
index 64bbcf436cb9ea46113f97a8302668d458cad767..9bbce563b61dc15d145e32aea675d50f52f30581 100644 (file)
@@ -64,8 +64,9 @@ pub struct CrateMetadata {
     pub extern_crate: Lock<Option<ExternCrate>>,
 
     pub blob: MetadataBlob,
-    pub cnum_map: Lock<CrateNumMap>,
+    pub cnum_map: CrateNumMap,
     pub cnum: CrateNum,
+    pub dependencies: Lock<Vec<CrateNum>>,
     pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
     pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,
 
@@ -96,32 +97,34 @@ pub struct CStore {
 impl CStore {
     pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
         CStore {
-            metas: RwLock::new(IndexVec::new()),
+            // We add an empty entry for LOCAL_CRATE (which maps to zero) in
+            // order to make array indices in `metas` match with the
+            // corresponding `CrateNum`. This first entry will always remain
+            // `None`.
+            metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
             extern_mod_crate_map: Lock::new(FxHashMap()),
             metadata_loader,
         }
     }
 
-    /// You cannot use this function to allocate a CrateNum in a thread-safe manner.
-    /// It is currently only used in CrateLoader which is single-threaded code.
-    pub fn next_crate_num(&self) -> CrateNum {
-        CrateNum::new(self.metas.borrow().len() + 1)
+    pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
+        let mut metas = self.metas.borrow_mut();
+        let cnum = CrateNum::new(metas.len());
+        metas.push(None);
+        cnum
     }
 
-    pub fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
+    pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
         self.metas.borrow()[cnum].clone().unwrap()
     }
 
-    pub fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
-        use rustc_data_structures::indexed_vec::Idx;
-        let mut met = self.metas.borrow_mut();
-        while met.len() <= cnum.index() {
-            met.push(None);
-        }
-        met[cnum] = Some(data);
+    pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
+        let mut metas = self.metas.borrow_mut();
+        assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
+        metas[cnum] = Some(data);
     }
 
-    pub fn iter_crate_data<I>(&self, mut i: I)
+    pub(super) fn iter_crate_data<I>(&self, mut i: I)
         where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
     {
         for (k, v) in self.metas.borrow().iter_enumerated() {
@@ -131,20 +134,22 @@ pub fn iter_crate_data<I>(&self, mut i: I)
         }
     }
 
-    pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
+    pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
         let mut ordering = Vec::new();
         self.push_dependencies_in_postorder(&mut ordering, krate);
         ordering.reverse();
         ordering
     }
 
-    pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
+    pub(super) fn push_dependencies_in_postorder(&self,
+                                                 ordering: &mut Vec<CrateNum>,
+                                                 krate: CrateNum) {
         if ordering.contains(&krate) {
             return;
         }
 
         let data = self.get_crate_data(krate);
-        for &dep in data.cnum_map.borrow().iter() {
+        for &dep in data.dependencies.borrow().iter() {
             if dep != krate {
                 self.push_dependencies_in_postorder(ordering, dep);
             }
@@ -153,7 +158,7 @@ pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate
         ordering.push(krate);
     }
 
-    pub fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
+    pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
         let mut ordering = Vec::new();
         for (num, v) in self.metas.borrow().iter_enumerated() {
             if let &Some(_) = v {
@@ -163,11 +168,11 @@ pub fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
         return ordering
     }
 
-    pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
+    pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
     }
 
-    pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
+    pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
     }
 }
index 57f92707ccfe332060a7ed943a7b9d4fa713f70b..53d1ff156274e796c855541d2aeef35699ec8d94 100644 (file)
@@ -246,7 +246,7 @@ fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
         if cnum == LOCAL_CRATE {
             self.cdata().cnum
         } else {
-            self.cdata().cnum_map.borrow()[cnum]
+            self.cdata().cnum_map[cnum]
         }
     }
 }
@@ -932,7 +932,7 @@ fn get_attributes(&self, item: &Entry<'tcx>, sess: &Session) -> Vec<ast::Attribu
     // Translate a DefId from the current compilation environment to a DefId
     // for an external crate.
     fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
-        for (local, &global) in self.cnum_map.borrow().iter_enumerated() {
+        for (local, &global) in self.cnum_map.iter_enumerated() {
             if global == did.krate {
                 return Some(DefId {
                     krate: local,
@@ -1007,7 +1007,7 @@ pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)>
             .enumerate()
             .flat_map(|(i, link)| {
                 let cnum = CrateNum::new(i + 1);
-                link.map(|link| (self.cnum_map.borrow()[cnum], link))
+                link.map(|link| (self.cnum_map[cnum], link))
             })
             .collect()
     }
index d7a06f7932fef396a8de850578e442efea6435a9..3de90abd9663f84213e90addb6ccd7292e228a9b 100644 (file)
@@ -929,10 +929,9 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
                 hir::ImplItemKind::Const(..) => true,
                 hir::ImplItemKind::Method(ref sig, _) => {
                     let generics = self.tcx.generics_of(def_id);
-                    let types = generics.parent_types as usize + generics.types.len();
-                    let needs_inline =
-                        (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline())
-                            && !self.metadata_output_only();
+                    let needs_inline = (generics.requires_monomorphization(self.tcx) ||
+                                        tcx.trans_fn_attrs(def_id).requests_inline()) &&
+                                        !self.metadata_output_only();
                     let is_const_fn = sig.constness == hir::Constness::Const;
                     let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
                     needs_inline || is_const_fn || always_encode_mir
index a99e0a32e6645bbf017f404815efcc21c36e619c..7ecf2eba43ddfe64232c90b93035df46e9772b53 100644 (file)
@@ -15,9 +15,8 @@
 #![feature(box_patterns)]
 #![feature(fs_read_write)]
 #![feature(libc)]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
 #![feature(proc_macro_internals)]
-#![feature(macro_lifetime_matcher)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
index 4d1f3e2b4300ab30a8ed6927cfe0029b6f78bca9..57b8824191f7b86ab50e1e02148e1eb35c129fcc 100644 (file)
@@ -1185,7 +1185,7 @@ fn new(origin: RegionVariableOrigin) -> Self {
 }
 
 impl fmt::Debug for Constraint {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(
             formatter,
             "({:?}: {:?} @ {:?}) due to {:?}",
index 42a1745addff75de36333f0f7047e59e2af05aea..1014299c708ddbcb4eb33d6ccda25cef9e0c71c6 100644 (file)
@@ -425,7 +425,7 @@ fn sanitize_projection(
             ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
                 ty: match base_ty.sty {
                     ty::TyArray(inner, size) => {
-                        let size = size.val.unwrap_u64();
+                        let size = size.unwrap_usize(tcx);
                         let min_size = (from as u64) + (to as u64);
                         if let Some(rest_size) = size.checked_sub(min_size) {
                             tcx.mk_array(inner, rest_size)
index 648746b6e9047d9e21978a1940990ff77c0a9187..20e11abca9fa0cf9eff30aa1ac1c92453151d7df 100644 (file)
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
 use hair::*;
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::region;
 use rustc::ty::{self, Ty, UpvarSubsts};
 use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::EvalErrorKind;
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -200,10 +199,10 @@ fn expr_as_rvalue(&mut self,
                             span: expr_span,
                             ty: this.hir.tcx().types.u32,
                             literal: Literal::Value {
-                                value: this.hir.tcx().mk_const(ty::Const {
-                                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                                    ty: this.hir.tcx().types.u32
-                                }),
+                                value: ty::Const::from_bits(
+                                    this.hir.tcx(),
+                                    0,
+                                    this.hir.tcx().types.u32),
                             },
                         }));
                         box AggregateKind::Generator(closure_id, substs, movability)
@@ -378,10 +377,7 @@ fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let bits = self.hir.integer_bit_width(ty);
         let n = (!0u128) >> (128 - bits);
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), n, ty)
         };
 
         self.literal_operand(span, ty, literal)
@@ -393,10 +389,7 @@ fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let bits = self.hir.integer_bit_width(ty);
         let n = 1 << (bits - 1);
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), n, ty)
         };
 
         self.literal_operand(span, ty, literal)
index d6ddfea1f19fb7dfd137360f0dcbd7a700f2b58b..913cb944835550be0e97234721aa643bcc5607ed 100644 (file)
@@ -122,12 +122,9 @@ pub fn add_cases_to_switch<'pat>(&mut self,
 
         match *match_pair.pattern.kind {
             PatternKind::Constant { value } => {
-                // if the places match, the type should match
-                assert_eq!(match_pair.pattern.ty, switch_ty);
-
                 indices.entry(value)
                        .or_insert_with(|| {
-                           options.push(value.val.to_raw_bits().expect("switching on int"));
+                           options.push(value.unwrap_bits(switch_ty));
                            options.len() - 1
                        });
                 true
index 6e10c2307c8e6879e29bf8b2e74ff7e6e1d6db07..6501dd00fe817493cf4fe50064ad697b7e0ea566 100644 (file)
@@ -13,9 +13,7 @@
 
 use build::Builder;
 
-use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
-use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc::mir::*;
 use syntax_pos::{Span, DUMMY_SP};
@@ -64,10 +62,7 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
             }
         }
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
         };
 
         self.literal_operand(span, ty, literal)
index 76605a7aa04840a05aac63af6f619f3a5a5883b8..3e432d84c699d2846be64074ff6d79edc46b578b 100644 (file)
@@ -14,8 +14,7 @@
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::hir::def::{Def, CtorKind};
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::interpret::GlobalId;
 use rustc::ty::{self, AdtKind, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
@@ -522,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 promoted: None
             };
             let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
-                Ok(cv) => cv.val.unwrap_u64(),
+                Ok(cv) => cv.unwrap_usize(cx.tcx),
                 Err(e) => {
                     e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
                     0
@@ -537,23 +536,19 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
         hir::ExprBreak(dest, ref value) => {
             match dest.target_id {
-                hir::ScopeTarget::Block(target_id) |
-                hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
+                Ok(target_id) => ExprKind::Break {
                     label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(target_id).local_id),
                     value: value.to_ref(),
                 },
-                hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
-                    bug!("invalid loop id for break: {}", err)
+                Err(err) => bug!("invalid loop id for break: {}", err)
             }
         }
         hir::ExprAgain(dest) => {
             match dest.target_id {
-                hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
-                hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
+                Ok(loop_id) => ExprKind::Continue {
                     label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(loop_id).local_id),
                 },
-                hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
-                    bug!("invalid loop id for continue: {}", err)
+                Err(err) => bug!("invalid loop id for continue: {}", err)
             }
         }
         hir::ExprMatch(ref discr, ref arms, _) => {
@@ -635,22 +630,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         span: expr.span,
                         kind: ExprKind::Literal {
                             literal: Literal::Value {
-                                value: cx.tcx().mk_const(ty::Const {
-                                    val,
-                                    ty,
-                                }),
+                                value: val,
                             },
                         },
                     }.to_ref();
-                    let offset = mk_const(
-                        ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
-                    );
+                    let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
                     match did {
                         Some(did) => {
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = Substs::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ConstVal::Unevaluated(did, substs));
+                            let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -707,10 +697,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx().mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty
-                }),
+                value: ty::Const::zero_sized(cx.tcx(), ty),
             },
         },
     }
@@ -764,20 +751,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty: cx.tables().node_id_to_type(expr.hir_id)
-                }),
+                value: ty::Const::zero_sized(
+                    cx.tcx,
+                    cx.tables().node_id_to_type(expr.hir_id)),
             },
         },
 
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Unevaluated(def_id, substs),
-                    ty: cx.tables().node_id_to_type(expr.hir_id)
-                }),
+                value: ty::Const::unevaluated(
+                    cx.tcx,
+                    def_id,
+                    substs,
+                    cx.tables().node_id_to_type(expr.hir_id))
             },
         },
 
index 5890ea5c9d0c653cc8d186986dbb1c4dd303ade1..4765a82d85b6c1bae1eeb5272e7a4b3badb3131f 100644 (file)
@@ -16,7 +16,6 @@
 
 use hair::*;
 
-use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
@@ -31,7 +30,6 @@
 use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc_data_structures::sync::Lrc;
-use rustc::mir::interpret::{Value, PrimVal};
 use hair::pattern::parse_float;
 
 #[derive(Clone)]
@@ -117,10 +115,7 @@ pub fn usize_ty(&mut self) -> Ty<'tcx> {
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
-                ty: self.tcx.types.usize
-            })
+            value: ty::Const::from_usize(self.tcx, value),
         }
     }
 
@@ -134,19 +129,13 @@ pub fn unit_ty(&mut self) -> Ty<'tcx> {
 
     pub fn true_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
-                ty: self.tcx.types.bool
-            })
+            value: ty::Const::from_bool(self.tcx, true),
         }
     }
 
     pub fn false_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                ty: self.tcx.types.bool
-            })
+            value: ty::Const::from_bool(self.tcx, false),
         }
     }
 
@@ -162,6 +151,7 @@ pub fn integer_bit_width(
         layout::Integer::from_attr(self.tcx, ty).size().bits()
     }
 
+    // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
     pub fn const_eval_literal(
         &mut self,
         lit: &'tcx ast::LitKind,
@@ -171,7 +161,7 @@ pub fn const_eval_literal(
     ) -> Literal<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
-        let parse_float = |num, fty| -> Value {
+        let parse_float = |num, fty| -> ConstValue<'tcx> {
             parse_float(num, fty, neg).unwrap_or_else(|_| {
                 // FIXME(#31407) this is only necessary because float parsing is buggy
                 self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
@@ -193,7 +183,7 @@ pub fn const_eval_literal(
                 let s = s.as_str();
                 let id = self.tcx.allocate_cached(s.as_bytes());
                 let ptr = MemoryPointer::new(id, 0);
-                Value::ByValPair(
+                ConstValue::ByValPair(
                     PrimVal::Ptr(ptr),
                     PrimVal::from_u128(s.len() as u128),
                 )
@@ -201,16 +191,16 @@ pub fn const_eval_literal(
             LitKind::ByteStr(ref data) => {
                 let id = self.tcx.allocate_cached(data);
                 let ptr = MemoryPointer::new(id, 0);
-                Value::ByVal(PrimVal::Ptr(ptr))
+                ConstValue::ByVal(PrimVal::Ptr(ptr))
             },
-            LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+            LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
             LitKind::Int(n, _) if neg => {
                 let n = n as i128;
                 let n = n.overflowing_neg().0;
                 let n = clamp(n as u128);
-                Value::ByVal(PrimVal::Bytes(n))
+                ConstValue::ByVal(PrimVal::Bytes(n))
             },
-            LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
+            LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))),
             LitKind::Float(n, fty) => {
                 parse_float(n, fty)
             }
@@ -221,14 +211,11 @@ pub fn const_eval_literal(
                 };
                 parse_float(n, fty)
             }
-            LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
-            LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+            LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+            LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
         };
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(lit),
-                ty,
-            }),
+            value: ty::Const::from_const_value(self.tcx, lit, ty)
         }
     }
 
@@ -258,11 +245,7 @@ pub fn trait_method(&mut self,
                 let method_ty = method_ty.subst(self.tcx, substs);
                 return (method_ty,
                         Literal::Value {
-                            value: self.tcx.mk_const(ty::Const {
-                                // ZST function type
-                                val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                                ty: method_ty
-                            }),
+                            value: ty::Const::zero_sized(self.tcx, method_ty)
                         });
             }
         }
index 1245f506955c133a4ebc2f51fc3d44b9850797bb..f930d47dc0bd37e3658f71c8a43bf35eabae4e73 100644 (file)
@@ -25,7 +25,6 @@
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc::mir::Field;
-use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::common::ErrorReported;
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -180,37 +179,34 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt
         self.byte_array_map.entry(pat).or_insert_with(|| {
             match pat.kind {
                 box PatternKind::Constant {
-                    value: &ty::Const { val: ConstVal::Value(b), ty }
+                    value: const_val
                 } => {
-                    match b {
-                        Value::ByVal(PrimVal::Ptr(ptr)) => {
-                            let is_array_ptr = ty
-                                .builtin_deref(true)
-                                .and_then(|t| t.ty.builtin_index())
-                                .map_or(false, |t| t == tcx.types.u8);
-                            assert!(is_array_ptr);
-                            let alloc = tcx
-                                .interpret_interner
-                                .get_alloc(ptr.alloc_id)
-                                .unwrap();
-                            assert_eq!(ptr.offset, 0);
-                            // FIXME: check length
-                            alloc.bytes.iter().map(|b| {
-                                &*pattern_arena.alloc(Pattern {
-                                    ty: tcx.types.u8,
-                                    span: pat.span,
-                                    kind: box PatternKind::Constant {
-                                        value: tcx.mk_const(ty::Const {
-                                            val: ConstVal::Value(Value::ByVal(
-                                                PrimVal::Bytes(*b as u128),
-                                            )),
-                                            ty: tcx.types.u8
-                                        })
-                                    }
-                                })
-                            }).collect()
-                        },
-                        _ => bug!("not a byte str: {:?}", b),
+                    if let Some(ptr) = const_val.to_ptr() {
+                        let is_array_ptr = const_val.ty
+                            .builtin_deref(true)
+                            .and_then(|t| t.ty.builtin_index())
+                            .map_or(false, |t| t == tcx.types.u8);
+                        assert!(is_array_ptr);
+                        let alloc = tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap();
+                        assert_eq!(ptr.offset, 0);
+                        // FIXME: check length
+                        alloc.bytes.iter().map(|b| {
+                            &*pattern_arena.alloc(Pattern {
+                                ty: tcx.types.u8,
+                                span: pat.span,
+                                kind: box PatternKind::Constant {
+                                    value: ty::Const::from_bits(
+                                        tcx,
+                                        *b as u128,
+                                        tcx.types.u8)
+                                }
+                            })
+                        }).collect()
+                    } else {
+                        bug!("not a byte str: {:?}", const_val)
                     }
                 }
                 _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
@@ -439,14 +435,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     match pcx.ty.sty {
         ty::TyBool => {
             [true, false].iter().map(|&b| {
-                ConstantValue(cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
-                    ty: cx.tcx.types.bool
-                }))
+                ConstantValue(ty::Const::from_bool(cx.tcx, b))
             }).collect()
         }
-        ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
-            let len = len.val.unwrap_u64();
+        ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
+            let len = len.unwrap_usize(cx.tcx);
             if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
@@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     for row in patterns {
         match *row.kind {
             PatternKind::Constant {
-                value: &ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
-                    ty,
+                value: const_val @ &ty::Const {
+                    val: ConstVal::Value(..),
+                    ..
                 }
             } => {
-                let is_array_ptr = ty
-                    .builtin_deref(true)
-                    .and_then(|t| t.ty.builtin_index())
-                    .map_or(false, |t| t == cx.tcx.types.u8);
-                if is_array_ptr {
-                    let alloc = cx.tcx
-                        .interpret_interner
-                        .get_alloc(ptr.alloc_id)
-                        .unwrap();
-                    max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                if let Some(ptr) = const_val.to_ptr() {
+                    let is_array_ptr = const_val.ty
+                        .builtin_deref(true)
+                        .and_then(|t| t.ty.builtin_index())
+                        .map_or(false, |t| t == cx.tcx.types.u8);
+                    if is_array_ptr {
+                        let alloc = cx.tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap();
+                        max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                    }
                 }
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
@@ -836,7 +831,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
 /// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
                           pat: &Pattern<'tcx>,
                           pcx: PatternContext)
                           -> Option<Vec<Constructor<'tcx>>>
@@ -854,7 +849,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
             Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::TyArray(_, length) => Some(vec![
-                Slice(length.val.unwrap_u64())
+                Slice(length.unwrap_usize(cx.tcx))
             ]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
@@ -934,27 +929,31 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
-                                    ctor: &Constructor,
-                                    prefix: &[Pattern],
-                                    slice: &Option<Pattern>,
-                                    suffix: &[Pattern])
-                                    -> Result<bool, ErrorReported> {
+fn slice_pat_covered_by_constructor<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, '_>,
+    _span: Span,
+    ctor: &Constructor,
+    prefix: &[Pattern<'tcx>],
+    slice: &Option<Pattern<'tcx>>,
+    suffix: &[Pattern<'tcx>]
+) -> Result<bool, ErrorReported> {
     let data: &[u8] = match *ctor {
-        ConstantValue(&ty::Const { val: ConstVal::Value(
-            Value::ByVal(PrimVal::Ptr(ptr))
-        ), ty }) => {
-            let is_array_ptr = ty
-                .builtin_deref(true)
-                .and_then(|t| t.ty.builtin_index())
-                .map_or(false, |t| t == tcx.types.u8);
-            assert!(is_array_ptr);
-            tcx
-                .interpret_interner
-                .get_alloc(ptr.alloc_id)
-                .unwrap()
-                .bytes
-                .as_ref()
+        ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
+            if let Some(ptr) = const_val.to_ptr() {
+                let is_array_ptr = const_val.ty
+                    .builtin_deref(true)
+                    .and_then(|t| t.ty.builtin_index())
+                    .map_or(false, |t| t == tcx.types.u8);
+                assert!(is_array_ptr);
+                tcx
+                    .interpret_interner
+                    .get_alloc(ptr.alloc_id)
+                    .unwrap()
+                    .bytes
+                    .as_ref()
+            } else {
+                bug!()
+            }
         }
         _ => bug!()
     };
@@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
             data[data.len()-suffix.len()..].iter().zip(suffix))
     {
         match pat.kind {
-            box PatternKind::Constant { value } => match value.val {
-                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
-                    assert_eq!(b as u8 as u128, b);
-                    if b as u8 != *ch {
-                        return Ok(false);
-                    }
+            box PatternKind::Constant { value } => {
+                let b = value.unwrap_bits(pat.ty);
+                assert_eq!(b as u8 as u128, b);
+                if b as u8 != *ch {
+                    return Ok(false);
                 }
-                _ => span_bug!(pat.span, "bad const u8 {:?}", value)
-            },
+            }
             _ => {}
         }
     }
@@ -987,8 +984,8 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
 
 fn constructor_covered_by_range<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    ctor: &Constructor,
-    from: &ConstVal, to: &ConstVal,
+    ctor: &Constructor<'tcx>,
+    from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
     end: RangeEnd,
     ty: Ty<'tcx>,
 ) -> Result<bool, ErrorReported> {
@@ -1006,22 +1003,22 @@ macro_rules! some_or_ok {
     }
     match *ctor {
         ConstantValue(value) => {
-            let to = some_or_ok!(cmp_to(&value.val));
+            let to = some_or_ok!(cmp_to(value));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&value.val)) && end)
+            Ok(some_or_ok!(cmp_from(value)) && end)
         },
         ConstantRange(from, to, RangeEnd::Included) => {
-            let to = some_or_ok!(cmp_to(&to.val));
+            let to = some_or_ok!(cmp_to(to));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+            Ok(some_or_ok!(cmp_from(from)) && end)
         },
         ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = some_or_ok!(cmp_to(&to.val));
+            let to = some_or_ok!(cmp_to(to));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+            Ok(some_or_ok!(cmp_from(from)) && end)
         }
         Single => Ok(true),
         _ => bug!(),
@@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
 
         PatternKind::Constant { value } => {
             match *constructor {
-                Slice(..) => match value.val {
-                    ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+                Slice(..) => {
+                    if let Some(ptr) = value.to_ptr() {
                         let is_array_ptr = value.ty
                             .builtin_deref(true)
                             .and_then(|t| t.ty.builtin_index())
@@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         } else {
                             None
                         }
-                    }
-                    _ => span_bug!(pat.span,
+                    } else {
+                        span_bug!(pat.span,
                         "unexpected const-val {:?} with ctor {:?}", value, constructor)
+                    }
                 },
                 _ => {
                     match constructor_covered_by_range(
                         cx.tcx,
-                        constructor, &value.val, &value.val, RangeEnd::Included,
+                        constructor, value, value, RangeEnd::Included,
                         value.ty,
                             ) {
                         Ok(true) => Some(vec![]),
@@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
         PatternKind::Range { lo, hi, ref end } => {
             match constructor_covered_by_range(
                 cx.tcx,
-                constructor, &lo.val, &hi.val, end.clone(), lo.ty,
+                constructor, lo, hi, end.clone(), lo.ty,
             ) {
                 Ok(true) => Some(vec![]),
                 Ok(false) => None,
index 2585447fa0a04f6cdecfe14bb2777a7a04fb4d31..749e574ff7ad41ca5bfa7420f2ded0f12825491f 100644 (file)
@@ -19,8 +19,8 @@
 use interpret::{const_val_field, const_variant_index, self};
 
 use rustc::middle::const_val::ConstVal;
-use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -124,24 +124,11 @@ pub enum PatternKind<'tcx> {
 
 fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
     match value.val {
-        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+        ConstVal::Value(..) => fmt_const_val(f, value),
         ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
-fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
-    use rustc::ty::TypeVariants::*;
-    match (value, &ty.sty) {
-        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
-        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
-            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
-        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
-    }
-}
-
 impl<'tcx> fmt::Display for Pattern<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.kind {
@@ -372,7 +359,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
                     (PatternKind::Constant { value: lo },
                      PatternKind::Constant { value: hi }) => {
                         use std::cmp::Ordering;
-                        match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
+                        match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) {
                             (RangeEnd::Excluded, Ordering::Less) =>
                                 PatternKind::Range { lo, hi, end },
                             (RangeEnd::Excluded, _) => {
@@ -616,7 +603,7 @@ fn slice_or_array_pattern(
 
             ty::TyArray(_, len) => {
                 // fixed-length array
-                let len = len.val.unwrap_u64();
+                let len = len.unwrap_usize(self.tcx);
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
@@ -740,8 +727,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                             self.tables.local_id_root.expect("literal outside any scope"),
                             self.substs,
                         );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                        *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
                     Err(()) => {
                         self.errors.push(PatternError::FloatBug);
@@ -762,8 +748,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                             self.tables.local_id_root.expect("literal outside any scope"),
                             self.substs,
                         );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                        *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
                     Err(()) => {
                         self.errors.push(PatternError::FloatBug);
@@ -866,7 +851,7 @@ fn const_to_pat(
             }
             ty::TyArray(_, n) => {
                 PatternKind::Array {
-                    prefix: (0..n.val.unwrap_u64())
+                    prefix: (0..n.unwrap_usize(self.tcx))
                         .map(|i| adt_subpattern(i as usize, None))
                         .collect(),
                     slice: None,
@@ -1049,45 +1034,48 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
 
 pub fn compare_const_vals<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    a: &ConstVal,
-    b: &ConstVal,
+    a: &'tcx ty::Const<'tcx>,
+    b: &'tcx ty::Const<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ordering> {
     trace!("compare_const_vals: {:?}, {:?}", a, b);
-    use rustc::mir::interpret::{Value, PrimVal};
-    match (a, b) {
-        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
-         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
-            use ::rustc_apfloat::Float;
-            match ty.sty {
-                ty::TyFloat(ast::FloatTy::F32) => {
-                    let l = ::rustc_apfloat::ieee::Single::from_bits(a);
-                    let r = ::rustc_apfloat::ieee::Single::from_bits(b);
-                    l.partial_cmp(&r)
-                },
-                ty::TyFloat(ast::FloatTy::F64) => {
-                    let l = ::rustc_apfloat::ieee::Double::from_bits(a);
-                    let r = ::rustc_apfloat::ieee::Double::from_bits(b);
-                    l.partial_cmp(&r)
-                },
-                ty::TyInt(_) => {
-                    let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
-                    let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
-                    Some((a as i128).cmp(&(b as i128)))
-                },
-                _ => Some(a.cmp(&b)),
-            }
-        },
-        _ if a == b => Some(Ordering::Equal),
-        _ => None,
+    // FIXME: This should use assert_bits(ty) instead of use_bits
+    // but triggers possibly bugs due to mismatching of arrays and slices
+    if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
+        use ::rustc_apfloat::Float;
+        match ty.sty {
+            ty::TyFloat(ast::FloatTy::F32) => {
+                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+                l.partial_cmp(&r)
+            },
+            ty::TyFloat(ast::FloatTy::F64) => {
+                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+                l.partial_cmp(&r)
+            },
+            ty::TyInt(_) => {
+                let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
+                let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
+                Some((a as i128).cmp(&(b as i128)))
+            },
+            _ => Some(a.cmp(&b)),
+        }
+    } else {
+        if a == b {
+            Some(Ordering::Equal)
+        } else {
+            None
+        }
     }
 }
 
+// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
 fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           ty: Ty<'tcx>,
                           neg: bool)
-                          -> Result<ConstVal<'tcx>, ()> {
+                          -> Result<&'tcx ty::Const<'tcx>, ()> {
     use syntax::ast::*;
 
     use rustc::mir::interpret::*;
@@ -1096,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             let s = s.as_str();
             let id = tcx.allocate_cached(s.as_bytes());
             let ptr = MemoryPointer::new(id, 0);
-            Value::ByValPair(
+            ConstValue::ByValPair(
                 PrimVal::Ptr(ptr),
                 PrimVal::from_u128(s.len() as u128),
             )
@@ -1104,9 +1092,9 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_cached(data);
             let ptr = MemoryPointer::new(id, 0);
-            Value::ByVal(PrimVal::Ptr(ptr))
+            ConstValue::ByVal(PrimVal::Ptr(ptr))
         },
-        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+        LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
         LitKind::Int(n, _) => {
             enum Int {
                 Signed(IntTy),
@@ -1119,31 +1107,28 @@ enum Int {
                 ty::TyUint(other) => Int::Unsigned(other),
                 _ => bug!(),
             };
+            // This converts from LitKind::Int (which is sign extended) to
+            // PrimVal::Bytes (which is zero extended)
             let n = match ty {
                 // FIXME(oli-obk): are these casts correct?
                 Int::Signed(IntTy::I8) if neg =>
-                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+                    (n as i8).overflowing_neg().0 as u8 as u128,
                 Int::Signed(IntTy::I16) if neg =>
-                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+                    (n as i16).overflowing_neg().0 as u16 as u128,
                 Int::Signed(IntTy::I32) if neg =>
-                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+                    (n as i32).overflowing_neg().0 as u32 as u128,
                 Int::Signed(IntTy::I64) if neg =>
-                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+                    (n as i64).overflowing_neg().0 as u64 as u128,
                 Int::Signed(IntTy::I128) if neg =>
                     (n as i128).overflowing_neg().0 as u128,
-                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
-                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
-                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
-                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
-                Int::Signed(IntTy::I128) => n,
-                Int::Unsigned(UintTy::U8) => n as u8 as u128,
-                Int::Unsigned(UintTy::U16) => n as u16 as u128,
-                Int::Unsigned(UintTy::U32) => n as u32 as u128,
-                Int::Unsigned(UintTy::U64) => n as u64 as u128,
-                Int::Unsigned(UintTy::U128) => n,
+                Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
+                Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
+                Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
+                Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
+                Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
                 _ => bug!(),
             };
-            Value::ByVal(PrimVal::Bytes(n))
+            ConstValue::ByVal(PrimVal::Bytes(n))
         },
         LitKind::Float(n, fty) => {
             parse_float(n, fty, neg)?
@@ -1155,17 +1140,17 @@ enum Int {
             };
             parse_float(n, fty, neg)?
         }
-        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
-        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+        LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+        LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
     };
-    Ok(ConstVal::Value(lit))
+    Ok(ty::Const::from_const_value(tcx, lit, ty))
 }
 
-pub fn parse_float(
+pub fn parse_float<'tcx>(
     num: Symbol,
     fty: ast::FloatTy,
     neg: bool,
-) -> Result<Value, ()> {
+) -> Result<ConstValue<'tcx>, ()> {
     let num = num.as_str();
     use rustc_apfloat::ieee::{Single, Double};
     use rustc_apfloat::Float;
@@ -1192,5 +1177,5 @@ pub fn parse_float(
         }
     };
 
-    Ok(Value::ByVal(PrimVal::Bytes(bits)))
+    Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
 }
index dff9fa271aba52f99b6b03c7ad54dbc03889bbd0..6bf965aaf44630079178dd4536be7f565a31782c 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::hir;
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
+use rustc::middle::const_val::{ConstEvalErr, ErrKind};
 use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt, Ty, Instance};
@@ -8,9 +8,13 @@
 
 use syntax::ast::Mutability;
 use syntax::codemap::Span;
+use syntax::codemap::DUMMY_SP;
 
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
-use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
+use rustc::mir::interpret::{
+    EvalResult, EvalError, EvalErrorKind, GlobalId,
+    Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
+};
+use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
 
 use std::fmt;
 use std::error::Error;
@@ -57,19 +61,21 @@ pub fn mk_eval_cx<'a, 'tcx>(
 }
 
 pub fn eval_promoted<'a, 'mir, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
     cid: GlobalId<'tcx>,
     mir: &'mir mir::Mir<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> Option<(Value, Pointer, Ty<'tcx>)> {
-    let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
-    match res {
-        Ok(val) => Some(val),
-        Err(mut err) => {
-            ecx.report(&mut err, false, None);
-            None
+    ecx.with_fresh_body(|ecx| {
+        let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
+        match res {
+            Ok(val) => Some(val),
+            Err(mut err) => {
+                ecx.report(&mut err, false, None);
+                None
+            }
         }
-    }
+    })
 }
 
 pub fn eval_body<'a, 'tcx>(
@@ -87,19 +93,76 @@ pub fn eval_body<'a, 'tcx>(
     }
 }
 
+pub fn value_to_const_value<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    val: Value,
+    ty: Ty<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
+    let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+
+    if layout.is_zst() {
+        return ty::Const::from_const_value(
+            tcx,
+            ConstValue::ByVal(PrimVal::Undef),
+            ty);
+    }
+
+    let val = match layout.abi {
+        layout::Abi::Scalar(..) => {
+            if let Value::ByVal(val) = val {
+                ConstValue::ByVal(val)
+            } else {
+                bug!("expected ByVal value, got {:?}", val);
+            }
+        }
+        layout::Abi::ScalarPair(..) => {
+            if let Value::ByValPair(a, b) = val {
+                ConstValue::ByValPair(a, b)
+            } else {
+                bug!("expected ByValPair value, got {:?}", val);
+            }
+        }
+        _ => {
+            if let Value::ByRef(ptr, align) = val {
+                let ptr = ptr.primval.to_ptr().unwrap();
+                assert_eq!(ptr.offset, 0);
+                let alloc = tcx.interpret_interner
+                               .get_alloc(ptr.alloc_id)
+                               .expect("miri allocation never successfully created");
+                assert_eq!(align, alloc.align);
+                ConstValue::ByRef(alloc)
+            } else {
+                bug!("expected ByRef value, got {:?}", val);
+            }
+        },
+    };
+    ty::Const::from_const_value(tcx, val, ty)
+}
+
 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cid: GlobalId<'tcx>,
     mir: Option<&'mir mir::Mir<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
-    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
     // we start out with the best span we have
     // and try improving it down the road when more information is available
     let span = tcx.def_span(cid.instance.def_id());
-    let mut span = mir.map(|mir| mir.span).unwrap_or(span);
+    let span = mir.map(|mir| mir.span).unwrap_or(span);
     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
-    let res = (|| {
+    let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
+    (r, ecx)
+}
+
+fn eval_body_using_ecx<'a, 'mir, 'tcx>(
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+    cid: GlobalId<'tcx>,
+    mir: Option<&'mir mir::Mir<'tcx>>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
+    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    let tcx = ecx.tcx.tcx;
         let mut mir = match mir {
             Some(mir) => mir,
             None => ecx.load_mir(cid.instance.def)?,
@@ -107,7 +170,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
         if let Some(index) = cid.promoted {
             mir = &mir.promoted[index];
         }
-        span = mir.span;
         let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
         assert!(!layout.is_unsized());
         let ptr = ecx.memory.allocate(
@@ -139,14 +201,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
         let ptr = ptr.into();
         // always try to read the value and report errors
         let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
-            // if it's a constant (so it needs no address, directly compute its value)
-            Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val,
+            Some(val) => val,
             // point at the allocation
             _ => Value::ByRef(ptr, layout.align),
         };
         Ok((value, ptr, layout.ty))
-    })();
-    (res, ecx)
 }
 
 pub struct CompileTimeEvaluator;
@@ -357,14 +416,16 @@ pub fn const_val_field<'a, 'tcx>(
     instance: ty::Instance<'tcx>,
     variant: Option<usize>,
     field: mir::Field,
-    value: Value,
+    value: ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> ::rustc::middle::const_val::EvalResult<'tcx> {
     trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
+        let value = ecx.const_value_to_value(value, ty)?;
         let (mut field, ty) = match value {
-            Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+            Value::ByValPair(..) | Value::ByVal(_) => 
+                ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
             Value::ByRef(ptr, align) => {
                 let place = Place::Ptr {
                     ptr,
@@ -385,10 +446,7 @@ pub fn const_val_field<'a, 'tcx>(
         Ok((field, ty))
     })();
     match result {
-        Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
-            val: ConstVal::Value(field),
-            ty,
-        })),
+        Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
         Err(err) => {
             let (trace, span) = ecx.generate_stacktrace(None);
             let err = ErrKind::Miri(err, trace);
@@ -404,15 +462,15 @@ pub fn const_variant_index<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     instance: ty::Instance<'tcx>,
-    value: Value,
+    val: ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> EvalResult<'tcx, usize> {
-    trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
+    trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let value = ecx.const_value_to_value(val, ty)?;
     let (ptr, align) = match value {
         Value::ByValPair(..) | Value::ByVal(_) => {
             let layout = ecx.layout_of(ty)?;
-            use super::MemoryKind;
             let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
             let ptr: Pointer = ptr.into();
             ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
@@ -424,6 +482,30 @@ pub fn const_variant_index<'a, 'tcx>(
     ecx.read_discriminant_as_variant_index(place, ty)
 }
 
+pub fn const_value_to_allocation_provider<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
+) -> &'tcx Allocation {
+    match val {
+        ConstValue::ByRef(alloc) => return alloc,
+        _ => ()
+    }
+    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
+        let mut ecx = EvalContext::new(
+            tcx.at(DUMMY_SP),
+            ty::ParamEnv::reveal_all(),
+            CompileTimeEvaluator,
+            ());
+        let value = ecx.const_value_to_value(val, ty)?;
+        let layout = ecx.layout_of(ty)?;
+        let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+        ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
+        let alloc = ecx.memory.get(ptr.alloc_id)?;
+        Ok(tcx.intern_const_alloc(alloc.clone()))
+    };
+    result().expect("unable to convert ConstVal to Allocation")
+}
+
 pub fn const_eval_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@@ -432,17 +514,6 @@ pub fn const_eval_provider<'a, 'tcx>(
     let cid = key.value;
     let def_id = cid.instance.def.def_id();
 
-    if tcx.is_foreign_item(def_id) {
-        let id = tcx.interpret_interner.cache_static(def_id);
-        let ty = tcx.type_of(def_id);
-        let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
-        let ptr = MemoryPointer::new(id, 0);
-        return Ok(tcx.mk_const(ty::Const {
-            val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
-            ty,
-        }))
-    }
-
     if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         let tables = tcx.typeck_tables_of(def_id);
         let span = tcx.def_span(def_id);
@@ -469,11 +540,8 @@ pub fn const_eval_provider<'a, 'tcx>(
     };
 
     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
-    res.map(|(miri_value, _, miri_ty)| {
-        tcx.mk_const(ty::Const {
-            val: ConstVal::Value(miri_value),
-            ty: miri_ty,
-        })
+    res.map(|(val, _, miri_ty)| {
+        value_to_const_value(tcx, val, miri_ty)
     }).map_err(|mut err| {
         if tcx.is_static(def_id).is_some() {
             ecx.report(&mut err, true, None);
index 3d670acf98cb2d3f20993f9fc7f8f96268613625..03137619edaf48d72a0780b073a6446cc575ec53 100644 (file)
@@ -15,7 +15,7 @@
 use syntax::ast::Mutability;
 use rustc::mir::interpret::{
     GlobalId, Value, Pointer, PrimVal, PrimValKind,
-    EvalError, EvalResult, EvalErrorKind, MemoryPointer,
+    EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
 };
 use std::mem;
 
@@ -116,15 +116,6 @@ pub struct ValTy<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-impl<'tcx> ValTy<'tcx> {
-    pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
-        match val.val {
-            ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
-            ConstVal::Unevaluated { .. } => None,
-        }
-    }
-}
-
 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
     type Target = Value;
     fn deref(&self) -> &Value {
@@ -183,6 +174,8 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
     }
 }
 
+const MAX_TERMINATORS: usize = 1_000_000;
+
 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn new(
         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
@@ -197,10 +190,19 @@ pub fn new(
             memory: Memory::new(tcx, memory_data),
             stack: Vec::new(),
             stack_limit: tcx.sess.const_eval_stack_frame_limit,
-            terminators_remaining: 1_000_000,
+            terminators_remaining: MAX_TERMINATORS,
         }
     }
 
+    pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
+        let stack = mem::replace(&mut self.stack, Vec::new());
+        let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
+        let r = f(self);
+        self.stack = stack;
+        self.terminators_remaining = terminators_remaining;
+        r
+    }
+
     pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
         let layout = self.layout_of(ty)?;
         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
@@ -235,7 +237,27 @@ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
         ))
     }
 
-    pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub fn const_value_to_value(
+        &mut self,
+        val: ConstValue<'tcx>,
+        _ty: Ty<'tcx>,
+    ) -> EvalResult<'tcx, Value> {
+        match val {
+            ConstValue::ByRef(alloc) => {
+                // FIXME: Allocate new AllocId for all constants inside
+                let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
+                Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
+            },
+            ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
+            ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
+        }
+    }
+
+    pub(super) fn const_to_value(
+        &mut self,
+        const_val: &ConstVal<'tcx>,
+        ty: Ty<'tcx>
+    ) -> EvalResult<'tcx, Value> {
         match *const_val {
             ConstVal::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
@@ -244,7 +266,7 @@ pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) ->
                     promoted: None,
                 }, ty)
             }
-            ConstVal::Value(val) => Ok(val),
+            ConstVal::Value(val) => self.const_value_to_value(val, ty)
         }
     }
 
@@ -568,7 +590,7 @@ pub(super) fn eval_rvalue_into_place(
 
             Repeat(ref operand, _) => {
                 let (elem_ty, length) = match dest_ty.sty {
-                    ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
+                    ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
                     _ => {
                         bug!(
                             "tried to assign array-repeat to non-array type {:?}",
@@ -592,7 +614,7 @@ pub(super) fn eval_rvalue_into_place(
                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
                 let ty = self.place_ty(place);
-                let (_, len) = src.elem_ty_and_len(ty);
+                let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
                 self.write_primval(
                     dest,
                     PrimVal::from_u128(len as u128),
@@ -822,8 +844,9 @@ pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValT
                     Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
 
                     Literal::Promoted { index } => {
+                        let instance = self.frame().instance;
                         self.read_global_as_value(GlobalId {
-                            instance: self.frame().instance,
+                            instance,
                             promoted: Some(index),
                         }, ty)?
                     }
@@ -997,7 +1020,7 @@ pub fn write_discriminant_value(
         Ok(())
     }
 
-    pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         if self.tcx.is_static(gid.instance.def_id()).is_some() {
             let alloc_id = self
                 .tcx
@@ -1341,92 +1364,84 @@ pub(crate) fn read_ptr(
         }
     }
 
-    pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
-        use syntax::ast::FloatTy;
-
-        let layout = self.layout_of(ty)?;
-        self.memory.check_align(ptr, ptr_align)?;
-
-        if layout.size.bytes() == 0 {
-            return Ok(Some(Value::ByVal(PrimVal::Undef)));
-        }
-
-        let ptr = ptr.to_ptr()?;
-        let val = match ty.sty {
+    pub fn validate_ptr_target(
+        &self,
+        ptr: MemoryPointer,
+        ptr_align: Align,
+        ty: Ty<'tcx>
+    ) -> EvalResult<'tcx> {
+        match ty.sty {
             ty::TyBool => {
                 let val = self.memory.read_primval(ptr, ptr_align, 1)?;
-                let val = match val {
-                    PrimVal::Bytes(0) => false,
-                    PrimVal::Bytes(1) => true,
+                match val {
+                    PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
                     // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
                     _ => return err!(InvalidBool),
-                };
-                PrimVal::from_bool(val)
+                }
             }
             ty::TyChar => {
                 let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
                 match ::std::char::from_u32(c) {
-                    Some(ch) => PrimVal::from_char(ch),
+                    Some(..) => (),
                     None => return err!(InvalidChar(c as u128)),
                 }
             }
 
-            ty::TyInt(int_ty) => {
-                use syntax::ast::IntTy::*;
-                let size = match int_ty {
-                    I8 => 1,
-                    I16 => 2,
-                    I32 => 4,
-                    I64 => 8,
-                    I128 => 16,
-                    Isize => self.memory.pointer_size(),
-                };
-                self.memory.read_primval(ptr, ptr_align, size)?
-            }
-
-            ty::TyUint(uint_ty) => {
-                use syntax::ast::UintTy::*;
-                let size = match uint_ty {
-                    U8 => 1,
-                    U16 => 2,
-                    U32 => 4,
-                    U64 => 8,
-                    U128 => 16,
-                    Usize => self.memory.pointer_size(),
-                };
-                self.memory.read_primval(ptr, ptr_align, size)?
-            }
-
-            ty::TyFloat(FloatTy::F32) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
-            }
-            ty::TyFloat(FloatTy::F64) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
-            }
-
-            ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
+            ty::TyFnPtr(_) => {
+                self.memory.read_ptr_sized(ptr, ptr_align)?;
+            },
             ty::TyRef(_, rty, _) |
             ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
-                return self.read_ptr(ptr, ptr_align, rty).map(Some)
+                self.read_ptr(ptr, ptr_align, rty)?;
             }
 
             ty::TyAdt(def, _) => {
                 if def.is_box() {
-                    return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
+                    self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
+                    return Ok(());
                 }
 
                 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
                     let size = scalar.value.size(self).bytes();
-                    self.memory.read_primval(ptr, ptr_align, size)?
-                } else {
-                    return Ok(None);
+                    self.memory.read_primval(ptr, ptr_align, size)?;
                 }
             }
 
-            _ => return Ok(None),
-        };
+            _ => (),
+        }
+        Ok(())
+    }
+
+    pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+        let layout = self.layout_of(ty)?;
+        self.memory.check_align(ptr, ptr_align)?;
 
-        Ok(Some(Value::ByVal(val)))
+        if layout.size.bytes() == 0 {
+            return Ok(Some(Value::ByVal(PrimVal::Undef)));
+        }
+
+        let ptr = ptr.to_ptr()?;
+
+        // Not the right place to do this
+        //self.validate_ptr_target(ptr, ptr_align, ty)?;
+
+        match layout.abi {
+            layout::Abi::Scalar(..) => {
+                let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
+                Ok(Some(Value::ByVal(primval)))
+            }
+            layout::Abi::ScalarPair(ref a, ref b) => {
+                let (a, b) = (&a.value, &b.value);
+                let (a_size, b_size) = (a.size(self), b.size(self));
+                let a_ptr = ptr;
+                let b_offset = a_size.abi_align(b.align(self));
+                let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
+                let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
+                let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
+                Ok(Some(Value::ByValPair(a_val, b_val)))
+            }
+            _ => Ok(None),
+        }
     }
 
     pub fn frame(&self) -> &Frame<'mir, 'tcx> {
@@ -1466,7 +1481,7 @@ fn unsize_into_ptr(
                 let ptr = self.into_ptr(src)?;
                 // u64 cast is from usize to u64, which is always good
                 let valty = ValTy {
-                    value: ptr.to_value_with_len(length.val.unwrap_u64() ),
+                    value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
                     ty: dest_ty,
                 };
                 self.write_value(valty, dest)
index 7f8205b8327face1250c757888a8dbfaaf8039d7..ba1c05deef1b42e8a0264c5ef4d7dc34223d14ce 100644 (file)
@@ -1,15 +1,18 @@
-use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
-use std::collections::{btree_map, BTreeMap, VecDeque};
-use std::{ptr, io};
+use std::collections::{btree_map, VecDeque};
+use std::ptr;
 
+use rustc::hir::def_id::DefId;
 use rustc::ty::Instance;
+use rustc::ty::ParamEnv;
 use rustc::ty::maps::TyCtxtAt;
 use rustc::ty::layout::{self, Align, TargetDataLayout};
 use syntax::ast::Mutability;
+use rustc::middle::const_val::{ConstVal, ErrKind};
 
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
-use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
-                            EvalResult, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
+                            EvalResult, PrimVal, EvalErrorKind, GlobalId};
+pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
 
 use super::{EvalContext, Machine};
 
@@ -79,20 +82,11 @@ pub fn allocate_cached(&mut self, bytes: &[u8]) -> MemoryPointer {
     }
 
     /// kind is `None` for statics
-    pub fn allocate(
+    pub fn allocate_value(
         &mut self,
-        size: u64,
-        align: Align,
+        alloc: Allocation,
         kind: Option<MemoryKind<M::MemoryKinds>>,
-    ) -> EvalResult<'tcx, MemoryPointer> {
-        assert_eq!(size as usize as u64, size);
-        let alloc = Allocation {
-            bytes: vec![0; size as usize],
-            relocations: BTreeMap::new(),
-            undef_mask: UndefMask::new(size),
-            align,
-            runtime_mutability: Mutability::Immutable,
-        };
+    ) -> EvalResult<'tcx, AllocId> {
         let id = self.tcx.interpret_interner.reserve();
         M::add_lock(self, id);
         match kind {
@@ -105,6 +99,17 @@ pub fn allocate(
                 self.uninitialized_statics.insert(id, alloc);
             },
         }
+        Ok(id)
+    }
+
+    /// kind is `None` for statics
+    pub fn allocate(
+        &mut self,
+        size: u64,
+        align: Align,
+        kind: Option<MemoryKind<M::MemoryKinds>>,
+    ) -> EvalResult<'tcx, MemoryPointer> {
+        let id = self.allocate_value(Allocation::undef(size, align), kind)?;
         Ok(MemoryPointer::new(id, 0))
     }
 
@@ -272,6 +277,31 @@ pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx>
 
 /// Allocation accessors
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+    fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
+        let instance = Instance::mono(self.tcx.tcx, def_id);
+        let gid = GlobalId {
+            instance,
+            promoted: None,
+        };
+        self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
+            match *err.kind {
+                ErrKind::Miri(ref err, _) => match err.kind {
+                    EvalErrorKind::TypeckError |
+                    EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+                    _ => EvalErrorKind::ReferencedConstant.into(),
+                },
+                ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+                ref other => bug!("const eval returned {:?}", other),
+            }
+        }).map(|val| {
+            let const_val = match val.val {
+                ConstVal::Value(val) => val,
+                ConstVal::Unevaluated(..) => bug!("should be evaluated"),
+            };
+            self.tcx.const_value_to_allocation((const_val, val.ty))
+        })
+    }
+
     pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
         // normal alloc?
         match self.alloc_map.get(&id) {
@@ -281,13 +311,19 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
                 Some(alloc) => Ok(alloc),
                 None => {
                     // static alloc?
-                    self.tcx.interpret_interner.get_alloc(id)
-                        // no alloc? produce an error
-                        .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
-                            EvalErrorKind::DerefFunctionPointer.into()
-                        } else {
-                            EvalErrorKind::DanglingPointerDeref.into()
-                        })
+                    if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
+                        return Ok(a);
+                    }
+                    // static variable?
+                    if let Some(did) = self.tcx.interpret_interner.get_static(id) {
+                        return self.const_eval_static(did);
+                    }
+                    // otherwise return an error
+                    Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
+                        EvalErrorKind::DerefFunctionPointer.into()
+                    } else {
+                        EvalErrorKind::DanglingPointerDeref.into()
+                    })
                 },
             },
         }
@@ -873,41 +909,6 @@ pub fn mark_definedness(
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Methods to access integers in the target endianness
-////////////////////////////////////////////////////////////////////////////////
-
-pub fn write_target_uint(
-    endianness: layout::Endian,
-    mut target: &mut [u8],
-    data: u128,
-) -> Result<(), io::Error> {
-    let len = target.len();
-    match endianness {
-        layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
-        layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
-    }
-}
-
-pub fn write_target_int(
-    endianness: layout::Endian,
-    mut target: &mut [u8],
-    data: i128,
-) -> Result<(), io::Error> {
-    let len = target.len();
-    match endianness {
-        layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
-        layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
-    }
-}
-
-pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
-    match endianness {
-        layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
-        layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Unaligned accesses
 ////////////////////////////////////////////////////////////////////////////////
index 1eb131810bdf38d9404a60a6fa16f61c4c3a9c17..d39bae5e8dbbaa1ca4ecc17539f5b6039af025a3 100644 (file)
     mk_borrowck_eval_cx,
     eval_body,
     CompileTimeEvaluator,
+    const_value_to_allocation_provider,
     const_eval_provider,
     const_val_field,
     const_variant_index,
+    value_to_const_value,
 };
 
 pub use self::machine::Machine;
index b5a06286e4eed18430d12f9460043b0ecd27d4aa..883b17b8584fb010ff322449d6262a5e4cced110 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -69,9 +69,13 @@ pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
         self.to_ptr_align().0.to_ptr()
     }
 
-    pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
+    pub(super) fn elem_ty_and_len(
+        self,
+        ty: Ty<'tcx>,
+        tcx: TyCtxt<'_, 'tcx, '_>
+    ) -> (Ty<'tcx>, u64) {
         match ty.sty {
-            ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
+            ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),
 
             ty::TySlice(elem) => {
                 match self {
@@ -320,7 +324,7 @@ pub fn place_index(
         let base = self.force_allocation(base)?;
         let (base_ptr, align) = base.to_ptr_align();
 
-        let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
+        let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
         let elem_size = self.layout_of(elem_ty)?.size.bytes();
         assert!(
             n < len,
@@ -396,7 +400,7 @@ pub fn eval_place_projection(
                 let base = self.force_allocation(base)?;
                 let (base_ptr, align) = base.to_ptr_align();
 
-                let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+                let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
                 let elem_size = self.layout_of(elem_ty)?.size.bytes();
                 assert!(n >= min_length as u64);
 
@@ -415,7 +419,7 @@ pub fn eval_place_projection(
                 let base = self.force_allocation(base)?;
                 let (base_ptr, align) = base.to_ptr_align();
 
-                let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+                let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
                 let elem_size = self.layout_of(elem_ty)?.size.bytes();
                 assert!(u64::from(from) <= n - u64::from(to));
                 let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
index 2545ba3a94af12215c6a4a15437304944a2ee358..fbc0facbc49670ca94fedbeef383d422780c83be 100644 (file)
@@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
     shim::provide(providers);
     transform::provide(providers);
     providers.const_eval = interpret::const_eval_provider;
+    providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
     providers.check_match = hair::pattern::check_match;
 }
 
index e051b848c011fe21a193cfc193fbf88719413b34..dc2009a02600309b79e35db58b221611e97411de 100644 (file)
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
+use rustc::mir::interpret::{AllocId, ConstValue};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::ty::subst::{Substs, Kind};
-use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::session::config;
 use rustc::mir::{self, Location, Promoted};
 use rustc::mir::visit::Visitor as MirVisitor;
 use rustc::mir::mono::MonoItem;
-use rustc::mir::interpret::GlobalId;
+use rustc::mir::interpret::{PrimVal, GlobalId};
 
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@@ -1076,7 +1076,7 @@ fn push_extra_entry_roots(&mut self) {
 
 fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
     let generics = tcx.generics_of(def_id);
-    generics.parent_types as usize + generics.types.len() > 0
+    generics.requires_monomorphization(tcx)
 }
 
 fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1108,14 +1108,18 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         continue;
                     }
 
-                    if !tcx.generics_of(method.def_id).types.is_empty() {
+                    if tcx.generics_of(method.def_id).own_counts().types != 0 {
                         continue;
                     }
 
-                    let substs = Substs::for_item(tcx,
-                                                  method.def_id,
-                                                  |_, _| tcx.types.re_erased,
-                                                  |def, _| trait_ref.substs.type_for_def(def));
+                    let substs = Substs::for_item(tcx, method.def_id, |param, _| {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+                            GenericParamDefKind::Type(_) => {
+                                trait_ref.substs[param.index as usize]
+                            }
+                        }
+                    });
 
                     let instance = ty::Instance::resolve(tcx,
                                                          ty::ParamEnv::reveal_all(),
@@ -1237,22 +1241,17 @@ fn collect_const<'a, 'tcx>(
     };
     match val {
         ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
-        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+        ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
             collect_miri(tcx, a.alloc_id, output);
             collect_miri(tcx, b.alloc_id, output);
         }
-        ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
-        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
-        ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
+        ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
+        ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
+        ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
             collect_miri(tcx, ptr.alloc_id, output),
-        ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
-            // by ref should only collect the inner allocation, not the value itself
-            let alloc = tcx
-                .interpret_interner
-                .get_alloc(ptr.alloc_id)
-                .expect("ByRef to extern static is not allowed");
-            for &inner in alloc.relocations.values() {
-                collect_miri(tcx, inner, output);
+        ConstVal::Value(ConstValue::ByRef(alloc)) => {
+            for &id in alloc.relocations.values() {
+                collect_miri(tcx, id, output);
             }
         }
         _ => {},
index 176ed8c5bca745c53e4c8f0cf2c7f80f9ba86bd7..a569ad00d0c65a6a3dcb211ef677964cc2dbbb86 100644 (file)
@@ -313,8 +313,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
             ty::TyArray(inner_type, len) => {
                 output.push('[');
                 self.push_type_name(inner_type, output);
-                write!(output, "; {}",
-                    len.val.unwrap_u64()).unwrap();
+                write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
                 output.push(']');
             },
             ty::TySlice(inner_type) => {
index 699a5b17435bd2c4161d8033eee349992cfc0d9f..c79298d8dd2cfa8a2dcbaf2432b33f32ab5fd53d 100644 (file)
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
-use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::maps::Providers;
-use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
@@ -303,7 +301,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
         ty::TyArray(ty, len) => {
-            let len = len.val.unwrap_u64();
+            let len = len.unwrap_usize(tcx);
             builder.array_shim(dest, src, ty, len)
         }
         ty::TyClosure(def_id, substs) => {
@@ -429,12 +427,12 @@ fn make_clone_call(
     ) {
         let tcx = self.tcx;
 
-        let substs = Substs::for_item(
-            tcx,
-            self.def_id,
-            |_, _| tcx.types.re_erased,
-            |_, _| ty
-        );
+        let substs = Substs::for_item(tcx, self.def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+                GenericParamDefKind::Type(_) => ty.into(),
+            }
+        });
 
         // `func == Clone::clone(&ty) -> ty`
         let func_ty = tcx.mk_fn_def(self.def_id, substs);
@@ -442,11 +440,7 @@ fn make_clone_call(
             span: self.span,
             ty: func_ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    // ZST function type
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty: func_ty
-                }),
+                value: ty::Const::zero_sized(self.tcx, func_ty)
             },
         });
 
@@ -506,10 +500,7 @@ fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
             span: self.span,
             ty: self.tcx.types.usize,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
-                    ty: self.tcx.types.usize,
-                })
+                value: ty::Const::from_usize(self.tcx, value),
             }
         }
     }
@@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 ty,
                 literal: Literal::Value {
-                    value: tcx.mk_const(ty::Const {
-                        // ZST function type
-                        val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                        ty
-                    }),
+                    value: ty::Const::zero_sized(tcx, ty)
                 },
              }),
              vec![rcvr])
index 2bf5a49c97e8ff31eaf648f27dc810065de63878..fc3764e4f49a5bbb8391ab4604b655c93340f9a5 100644 (file)
@@ -357,7 +357,7 @@ fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: D
 
     // FIXME: when we make this a hard error, this should have its
     // own error code.
-    let message = if !tcx.generics_of(def_id).types.is_empty() {
+    let message = if tcx.generics_of(def_id).own_counts().types != 0 {
         format!("#[derive] can't be used on a #[repr(packed)] struct with \
                  type parameters (error E0133)")
     } else {
index e1db216b6bbbcfad1b1d15a9a696d79cc3325674..80603959ec202fdd0542d64941bedd7c2ff94a0b 100644 (file)
 use rustc::mir::visit::{Visitor, PlaceContext};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{TyCtxt, self, Instance};
-use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
+use interpret::EvalContext;
+use interpret::CompileTimeEvaluator;
 use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
 use transform::{MirPass, MirSource};
-use syntax::codemap::Span;
+use syntax::codemap::{Span, DUMMY_SP};
 use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::ty::ParamEnv;
 use rustc::ty::layout::{
-    LayoutOf, TyLayout, LayoutError,
+    LayoutOf, TyLayout, LayoutError, LayoutCx,
     HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
 
@@ -64,6 +66,7 @@ fn run_pass<'a, 'tcx>(&self,
 
 /// Finds optimization opportunities on the MIR.
 struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
+    ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
     mir: &'b Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     source: MirSource,
@@ -102,7 +105,11 @@ fn new(
         source: MirSource,
     ) -> ConstPropagator<'b, 'a, 'tcx> {
         let param_env = tcx.param_env(source.def_id);
+        let substs = Substs::identity_for_item(tcx, source.def_id);
+        let instance = Instance::new(source.def_id, substs);
+        let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
         ConstPropagator {
+            ecx,
             mir,
             tcx,
             source,
@@ -112,7 +119,27 @@ fn new(
         }
     }
 
-    fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+    fn use_ecx<F, T>(
+        &mut self,
+        span: Span,
+        f: F
+    ) -> Option<T>
+    where
+        F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
+    {
+        self.ecx.tcx.span = span;
+        let r = match f(self) {
+            Ok(val) => Some(val),
+            Err(mut err) => {
+                self.ecx.report(&mut err, false, Some(span));
+                None
+            },
+        };
+        self.ecx.tcx.span = DUMMY_SP;
+        r
+    }
+
+    fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
         let value = match self.tcx.const_eval(self.param_env.and(cid)) {
             Ok(val) => val,
             Err(err) => {
@@ -121,7 +148,9 @@ fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
             },
         };
         let val = match value.val {
-            ConstVal::Value(v) => v,
+            ConstVal::Value(v) => {
+                self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
+            },
             _ => bug!("eval produced: {:?}", value),
         };
         let val = (val, value.ty, span);
@@ -132,7 +161,12 @@ fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
     fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
         match c.literal {
             Literal::Value { value } => match value.val {
-                ConstVal::Value(v) => Some((v, value.ty, c.span)),
+                ConstVal::Value(v) => {
+                    let v = self.use_ecx(c.span, |this| {
+                        this.ecx.const_value_to_value(v, value.ty)
+                    })?;
+                    Some((v, value.ty, c.span))
+                },
                 ConstVal::Unevaluated(did, substs) => {
                     let instance = Instance::resolve(
                         self.tcx,
@@ -150,7 +184,7 @@ fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
             // evaluate the promoted and replace the constant with the evaluated result
             Literal::Promoted { index } => {
                 let generics = self.tcx.generics_of(self.source.def_id);
-                if generics.parent_types as usize + generics.types.len() > 0 {
+                if generics.requires_monomorphization(self.tcx) {
                     // FIXME: can't handle code with generics
                     return None;
                 }
@@ -162,7 +196,10 @@ fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
                 };
                 // cannot use `const_eval` here, because that would require having the MIR
                 // for the current function available, but we're producing said MIR right now
-                let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
+                let span = self.mir.span;
+                let (value, _, ty) = self.use_ecx(span, |this| {
+                    Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
+                })??;
                 let val = (value, ty, c.span);
                 trace!("evaluated {:?} to {:?}", c, val);
                 Some(val)
@@ -185,7 +222,11 @@ fn eval_place(&mut self, place: &Place<'tcx>) -> Option<Const<'tcx>> {
                             use rustc_data_structures::indexed_vec::Idx;
                             let field_index = field.index();
                             let val = [a, b][field_index];
-                            let field = base_layout.field(&*self, field_index).ok()?;
+                            let cx = LayoutCx {
+                                tcx: self.tcx,
+                                param_env: self.param_env,
+                            };
+                            let field = base_layout.field(cx, field_index).ok()?;
                             trace!("projection resulted in: {:?}", val);
                             Some((Value::ByVal(val), field.ty, span))
                         },
@@ -254,23 +295,17 @@ fn const_prop(
                     self.source.def_id
                 };
                 let generics = self.tcx.generics_of(def_id);
-                if generics.parent_types as usize + generics.types.len() > 0 {
+                if generics.requires_monomorphization(self.tcx) {
                     // FIXME: can't handle code with generics
                     return None;
                 }
-                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
-                let instance = Instance::new(self.source.def_id, substs);
-                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
 
                 let val = self.eval_operand(arg)?;
-                let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
-                match ecx.unary_op(op, prim, val.1) {
-                    Ok(val) => Some((Value::ByVal(val), place_ty, span)),
-                    Err(mut err) => {
-                        ecx.report(&mut err, false, Some(span));
-                        None
-                    },
-                }
+                let prim = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
+                })?;
+                let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
+                Some((Value::ByVal(val), place_ty, span))
             }
             Rvalue::CheckedBinaryOp(op, ref left, ref right) |
             Rvalue::BinaryOp(op, ref left, ref right) => {
@@ -282,16 +317,14 @@ fn const_prop(
                     self.source.def_id
                 };
                 let generics = self.tcx.generics_of(def_id);
-                let has_generics = generics.parent_types as usize + generics.types.len() > 0;
-                if has_generics {
+                if generics.requires_monomorphization(self.tcx) {
                     // FIXME: can't handle code with generics
                     return None;
                 }
-                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
-                let instance = Instance::new(self.source.def_id, substs);
-                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
 
-                let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
+                let r = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
+                })?;
                 if op == BinOp::Shr || op == BinOp::Shl {
                     let param_env = self.tcx.param_env(self.source.def_id);
                     let left_ty = left.ty(self.mir, self.tcx);
@@ -316,31 +349,31 @@ fn const_prop(
                     }
                 }
                 let left = self.eval_operand(left)?;
-                let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+                let l = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
+                })?;
                 trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
-                match ecx.binary_op(op, l, left.1, r, right.1) {
-                    Ok((val, overflow)) => {
-                        let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
-                            Value::ByValPair(
-                                val,
-                                PrimVal::from_bool(overflow),
-                            )
-                        } else {
-                            if overflow {
-                                use rustc::mir::interpret::EvalErrorKind;
-                                let mut err = EvalErrorKind::Overflow(op).into();
-                                ecx.report(&mut err, false, Some(span));
-                                return None;
-                            }
-                            Value::ByVal(val)
-                        };
-                        Some((val, place_ty, span))
-                    },
-                    Err(mut err) => {
-                        ecx.report(&mut err, false, Some(span));
-                        None
-                    },
-                }
+                let (val, overflow) = self.use_ecx(span, |this| {
+                    this.ecx.binary_op(op, l, left.1, r, right.1)
+                })?;
+                let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
+                    Value::ByValPair(
+                        val,
+                        PrimVal::from_bool(overflow),
+                    )
+                } else {
+                    if overflow {
+                        use rustc::mir::interpret::EvalErrorKind;
+                        let mut err = EvalErrorKind::Overflow(op).into();
+                        self.use_ecx(span, |this| {
+                            this.ecx.report(&mut err, false, Some(span));
+                            Ok(())
+                        });
+                        return None;
+                    }
+                    Value::ByVal(val)
+                };
+                Some((val, place_ty, span))
             },
         }
     }
index 5397d18cdd720be1b0d185fe4359e88d10bb07d3..56050318ca7faf808687a0dd313110f83d996ded 100644 (file)
@@ -17,8 +17,6 @@
 use dataflow::{self, do_dataflow, DebugFormatted};
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_set::IdxSetBuf;
 use rustc_data_structures::indexed_vec::Idx;
@@ -174,7 +172,7 @@ struct Elaborator<'a, 'b: 'a, 'tcx: 'b> {
 }
 
 impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
         Ok(())
     }
 }
@@ -533,10 +531,7 @@ fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
             span,
             ty: self.tcx.types.bool,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
-                    ty: self.tcx.types.bool
-                })
+                value: ty::Const::from_bool(self.tcx, val)
             }
         })))
     }
index c4e700cdd1f41aa2d62c720dc0a2d0ef5b2f9a72..5da40d04b337399b6526b5bcf64b43c4267bd098 100644 (file)
@@ -61,7 +61,6 @@
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty};
@@ -79,7 +78,6 @@
 use transform::no_landing_pads::no_landing_pads;
 use dataflow::{do_dataflow, DebugFormatted, state_for_location};
 use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
-use rustc::mir::interpret::{Value, PrimVal};
 
 pub struct StateTransform;
 
@@ -180,10 +178,10 @@ fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx>
             span: source_info.span,
             ty: self.tcx.types.u32,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
-                    ty: self.tcx.types.u32
-                }),
+                value: ty::Const::from_bits(
+                    self.tcx,
+                    state_disc.into(),
+                    self.tcx.types.u32),
             },
         });
         Statement {
@@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                    ty: tcx.types.bool
-                }),
+                value: ty::Const::from_bool(tcx, false),
             },
         }),
         expected: true,
index 4762c6aaa27cc8143e78f65ffe3058c493a67d62..28ab3d6a8574fb3543cf27bc40e15f42192cb97d 100644 (file)
@@ -595,7 +595,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
             }
             Operand::Constant(ref constant) => {
                 if let Literal::Value {
-                    value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
+                    value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
                 } = constant.literal {
                     // Don't peek inside trait associated constants.
                     if self.tcx.trait_of_item(def_id).is_some() {
@@ -690,7 +690,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                             _ => false
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.val.unwrap_u64() == 0 &&
+                        len.unwrap_usize(self.tcx) == 0 &&
                             self.mode == Mode::Fn
                     } else {
                         false
index 9dd48952208a9bed86565fb603ffdbaca8bf1927..72bee040c06a9a676f5b5b3c5fcad9fc00511acc 100644 (file)
 
 //! A pass that simplifies branches when their condition is known.
 
-use rustc::ty::{self, TyCtxt};
-use rustc::middle::const_val::ConstVal;
+use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal};
 use transform::{MirPass, MirSource};
 
 use std::borrow::Cow;
@@ -32,7 +30,7 @@ fn name<'a>(&'a self) -> Cow<'a, str> {
     }
 
     fn run_pass<'a, 'tcx>(&self,
-                          _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           _src: MirSource,
                           mir: &mut Mir<'tcx>) {
         for block in mir.basic_blocks_mut() {
@@ -40,8 +38,8 @@ fn run_pass<'a, 'tcx>(&self,
             terminator.kind = match terminator.kind {
                 TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
-                }), ref values, ref targets, .. } => {
-                    if let Some(constint) = value.val.to_raw_bits() {
+                }), switch_ty, ref values, ref targets, .. } => {
+                    if let Some(constint) = value.assert_bits(switch_ty) {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
                         for (&v, t) in values.iter().zip(targets.iter()) {
@@ -57,12 +55,9 @@ fn run_pass<'a, 'tcx>(&self,
                 },
                 TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
-                        value: &ty::Const {
-                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
-                        .. }
+                        value
                     }, ..
-                }), expected, .. } if (cond == 1) == expected => {
-                    assert!(cond <= 1);
+                }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
                     TerminatorKind::Goto { target: target }
                 },
                 TerminatorKind::FalseEdges { real_target, .. } => {
index 9cc3ffb30638fe78945d485a482235b0ee7e0f92..5019c74742a2b3ff31ddc087b85883ae5a1de196 100644 (file)
@@ -81,9 +81,9 @@ fn visit_assign(&mut self,
                 } else {
                     let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
                     if let ty::TyArray(item_ty, const_size) = place_ty.sty {
-                        if let Some(size) = const_size.val.to_raw_bits() {
-                            assert!(size <= (u32::max_value() as u128),
-                                    "unform array move out doesn't supported
+                        if let Some(size) = const_size.assert_usize(self.tcx) {
+                            assert!(size <= u32::max_value() as u64,
+                                    "uniform array move out doesn't supported
                                      for array bigger then u32");
                             self.uniform(location, dst_place, proj, item_ty, size as u32);
                         }
@@ -203,7 +203,7 @@ fn run_pass<'a, 'tcx>(&self,
                         let opt_size = opt_src_place.and_then(|src_place| {
                             let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
                             if let ty::TyArray(_, ref size_o) = src_ty.sty {
-                                size_o.val.to_raw_bits().map(|n| n as u64)
+                                size_o.assert_usize(tcx)
                             } else {
                                 None
                             }
index a641cf3d93ecfeff5dab38d05389ee2c448a5761..9fc04dc7d24914a3c66fca69418aeaa2cf984799 100644 (file)
@@ -11,7 +11,6 @@
 use std::fmt;
 use rustc::hir;
 use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -19,7 +18,6 @@
 use rustc::ty::util::IntTypeExt;
 use rustc_data_structures::indexed_vec::Idx;
 use util::patch::MirPatch;
-use rustc::mir::interpret::{Value, PrimVal};
 
 use std::{iter, u32};
 
@@ -809,8 +807,10 @@ fn open_drop<'a>(&mut self) -> BasicBlock {
                 let succ = self.succ;
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
-            ty::TyArray(ety, size) => self.open_drop_for_array(
-                ety, size.val.to_raw_bits().map(|i| i as u64)),
+            ty::TyArray(ety, size) => {
+                let size = size.assert_usize(self.tcx());
+                self.open_drop_for_array(ety, size)
+            },
             ty::TySlice(ety) => self.open_drop_for_array(ety, None),
 
             _ => bug!("open drop from non-ADT `{:?}`", ty)
@@ -961,10 +961,7 @@ fn constant_usize(&self, val: u16) -> Operand<'tcx> {
             span: self.source_info.span,
             ty: self.tcx().types.usize,
             literal: Literal::Value {
-                value: self.tcx().mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
-                    ty: self.tcx().types.usize
-                })
+                value: ty::Const::from_usize(self.tcx(), val.into())
             }
         })
     }
index 71012ca6d5f7992045124a4af6997ed39a65351d..9d74ad0830f0c236178cc1227b48e0a81ac1fa45 100644 (file)
@@ -402,7 +402,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
 
     fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
         self.super_const(constant);
-        let ty::Const { ty, val } = constant;
+        let ty::Const { ty, val, .. } = constant;
         self.push(&format!("ty::Const"));
         self.push(&format!("+ ty: {:?}", ty));
         self.push(&format!("+ val: {:?}", val));
index 6708640379a54d2157a5f5adaba426a4d35c1d76..4789e2e50ca540cc2d99f565b4bb330c07652302 100644 (file)
@@ -114,7 +114,7 @@ fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait:
         }
     }
 
-    /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus),
+    /// matches '-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus),
     /// or path for ranges.
     ///
     /// FIXME: do we want to allow expr -> pattern conversion to create path expressions?
index 008c71cc9ce3d2129a892f08753ff1c4e2eb8faa..81299f4ba9f66cf004732458ec7ed8cc683e70aa 100644 (file)
@@ -85,20 +85,21 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
                 self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
-                let loop_id = match label.target_id {
-                    hir::ScopeTarget::Block(_) => return,
-                    hir::ScopeTarget::Loop(loop_res) => {
-                        match loop_res.into() {
-                            Ok(loop_id) => loop_id,
-                            Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
-                            Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                                self.emit_unlabled_cf_in_while_condition(e.span, "break");
-                                ast::DUMMY_NODE_ID
-                            },
-                            Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
-                        }
-                    }
+                let loop_id = match label.target_id.into() {
+                    Ok(loop_id) => loop_id,
+                    Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
+                    Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+                        self.emit_unlabled_cf_in_while_condition(e.span, "break");
+                        ast::DUMMY_NODE_ID
+                    },
+                    Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
                 };
+                if loop_id != ast::DUMMY_NODE_ID {
+                    match self.hir_map.find(loop_id).unwrap() {
+                        hir::map::NodeBlock(_) => return,
+                        _=> (),
+                    }
+                }
 
                 if opt_expr.is_some() {
                     let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
@@ -132,9 +133,7 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
                 self.require_loop("break", e.span);
             }
             hir::ExprAgain(label) => {
-                if let hir::ScopeTarget::Loop(
-                    hir::LoopIdResult::Err(
-                        hir::LoopIdError::UnlabeledCfInWhileCondition)) = label.target_id {
+                if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.target_id {
                     self.emit_unlabled_cf_in_while_condition(e.span, "continue");
                 }
                 self.require_loop("continue", e.span)
index ee08e6223903e39e9079c332d73189d08072c947..6e9b03cd2a9c6cedb35d803f4c1fa0d421f6c6d2 100644 (file)
 use rustc::hir::itemlikevisit::DeepVisitor;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
-use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable, GenericParamDefKind};
 use rustc::ty::fold::TypeVisitor;
 use rustc::ty::maps::Providers;
+use rustc::ty::subst::UnpackedKind;
 use rustc::util::nodemap::NodeSet;
 use syntax::ast::{self, CRATE_NODE_ID, Ident};
 use syntax::symbol::keywords;
@@ -37,6 +38,7 @@
 
 use std::cmp;
 use std::mem::replace;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 
 mod diagnostics;
@@ -397,9 +399,14 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
 
 impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        for def in &self.ev.tcx.generics_of(self.item_def_id).types {
-            if def.has_default {
-                self.ev.tcx.type_of(def.def_id).visit_with(self);
+        for param in &self.ev.tcx.generics_of(self.item_def_id).params {
+            match param.kind {
+                GenericParamDefKind::Type(ty) => {
+                    if ty.has_default {
+                        self.ev.tcx.type_of(param.def_id).visit_with(self);
+                    }
+                }
+                GenericParamDefKind::Lifetime => {}
             }
         }
         self
@@ -624,6 +631,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
     in_body: bool,
     span: Span,
     empty_tables: &'a ty::TypeckTables<'tcx>,
+    visited_anon_tys: FxHashSet<DefId>
 }
 
 impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
@@ -943,8 +951,15 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
                             self.tcx.sess.span_err(self.span, &msg);
                             return true;
                         }
-                        // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
-                        for subst in trait_ref.substs.iter().skip(1) {
+                        for subst in trait_ref.substs.iter() {
+                            // Skip repeated `TyAnon`s to avoid infinite recursion.
+                            if let UnpackedKind::Type(ty) = subst.unpack() {
+                                if let ty::TyAnon(def_id, ..) = ty.sty {
+                                    if !self.visited_anon_tys.insert(def_id) {
+                                        continue;
+                                    }
+                                }
+                            }
                             if subst.visit_with(self) {
                                 return true;
                             }
@@ -1325,9 +1340,14 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        for def in &self.tcx.generics_of(self.item_def_id).types {
-            if def.has_default {
-                self.tcx.type_of(def.def_id).visit_with(self);
+        for param in &self.tcx.generics_of(self.item_def_id).params {
+            match param.kind {
+                GenericParamDefKind::Type(ty) => {
+                    if ty.has_default {
+                        self.tcx.type_of(param.def_id).visit_with(self);
+                    }
+                }
+                GenericParamDefKind::Lifetime => {}
             }
         }
         self
@@ -1677,6 +1697,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         in_body: false,
         span: krate.span,
         empty_tables: &empty_tables,
+        visited_anon_tys: FxHashSet()
     };
     intravisit::walk_crate(&mut visitor, krate);
 
index 976614c9542a8255e3f99a21635024074348dad1..7b94170ef6d992f1cbc71dafeb6ed1edd65bab69 100644 (file)
@@ -16,7 +16,7 @@ rustc_target = { path = "../librustc_target" }
 rustc_typeck = { path = "../librustc_typeck" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-rls-data = "0.15"
+rls-data = "0.16"
 rls-span = "0.4"
 # FIXME(#40527) should move rustc serialize out of tree
 rustc-serialize = "0.3"
index abaa02a856e9cae181944eda5a8fed471205c308..2ef294fe43089f8fe9d4cd901f807798478733d9 100644 (file)
@@ -268,80 +268,6 @@ fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
         }
     }
 
-    fn process_def_kind(
-        &mut self,
-        ref_id: NodeId,
-        span: Span,
-        sub_span: Option<Span>,
-        def_id: DefId,
-    ) {
-        if self.span.filter_generated(sub_span, span) {
-            return;
-        }
-
-        let def = self.save_ctxt.get_path_def(ref_id);
-        match def {
-            HirDef::Mod(_) => {
-                let span = self.span_from_span(sub_span.expect("No span found for mod ref"));
-                self.dumper.dump_ref(Ref {
-                    kind: RefKind::Mod,
-                    span,
-                    ref_id: ::id_from_def_id(def_id),
-                });
-            }
-            HirDef::Struct(..) |
-            HirDef::Variant(..) |
-            HirDef::Union(..) |
-            HirDef::Enum(..) |
-            HirDef::TyAlias(..) |
-            HirDef::TyForeign(..) |
-            HirDef::TraitAlias(..) |
-            HirDef::Trait(_) => {
-                let span = self.span_from_span(sub_span.expect("No span found for type ref"));
-                self.dumper.dump_ref(Ref {
-                    kind: RefKind::Type,
-                    span,
-                    ref_id: ::id_from_def_id(def_id),
-                });
-            }
-            HirDef::Static(..) |
-            HirDef::Const(..) |
-            HirDef::StructCtor(..) |
-            HirDef::VariantCtor(..) => {
-                let span = self.span_from_span(sub_span.expect("No span found for var ref"));
-                self.dumper.dump_ref(Ref {
-                    kind: RefKind::Variable,
-                    span,
-                    ref_id: ::id_from_def_id(def_id),
-                });
-            }
-            HirDef::Fn(..) => {
-                let span = self.span_from_span(sub_span.expect("No span found for fn ref"));
-                self.dumper.dump_ref(Ref {
-                    kind: RefKind::Function,
-                    span,
-                    ref_id: ::id_from_def_id(def_id),
-                });
-            }
-            // With macros 2.0, we can legitimately get a ref to a macro, but
-            // we don't handle it properly for now (FIXME).
-            HirDef::Macro(..) => {}
-            HirDef::Local(..) |
-            HirDef::Upvar(..) |
-            HirDef::SelfTy(..) |
-            HirDef::Label(_) |
-            HirDef::TyParam(..) |
-            HirDef::Method(..) |
-            HirDef::AssociatedTy(..) |
-            HirDef::AssociatedConst(..) |
-            HirDef::PrimTy(_) |
-            HirDef::GlobalAsm(_) |
-            HirDef::Err => {
-                span_bug!(span, "process_def_kind for unexpected item: {:?}", def);
-            }
-        }
-    }
-
     fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) {
         for arg in formals {
             self.visit_pat(&arg.pat);
@@ -1348,29 +1274,17 @@ fn process_use_tree(&mut self,
                 };
 
                 let sub_span = self.span.span_for_last_ident(path.span);
-                let mod_id = match self.lookup_def_id(id) {
-                    Some(def_id) => {
-                        self.process_def_kind(id, path.span, sub_span, def_id);
-                        Some(def_id)
-                    }
-                    None => None,
-                };
-
-                // 'use' always introduces an alias, if there is not an explicit
-                // one, there is an implicit one.
-                let sub_span = match self.span.sub_span_after_keyword(use_tree.span,
-                                                                      keywords::As) {
-                    Some(sub_span) => Some(sub_span),
-                    None => sub_span,
-                };
+                let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As);
+                let ref_id = self.lookup_def_id(id);
 
                 if !self.span.filter_generated(sub_span, path.span) {
-                    let span =
-                        self.span_from_span(sub_span.expect("No span found for use"));
+                    let span = self.span_from_span(sub_span.expect("No span found for use"));
+                    let alias_span = alias_span.map(|sp| self.span_from_span(sp));
                     self.dumper.import(&access, Import {
                         kind: ImportKind::Use,
-                        ref_id: mod_id.map(|id| ::id_from_def_id(id)),
+                        ref_id: ref_id.map(|id| ::id_from_def_id(id)),
                         span,
+                        alias_span,
                         name: ident.to_string(),
                         value: String::new(),
                         parent,
@@ -1407,6 +1321,7 @@ fn process_use_tree(&mut self,
                         kind: ImportKind::GlobUse,
                         ref_id: None,
                         span,
+                        alias_span: None,
                         name: "*".to_owned(),
                         value: names.join(", "),
                         parent,
@@ -1500,6 +1415,7 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                             kind: ImportKind::ExternCrate,
                             ref_id: None,
                             span,
+                            alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
                             parent,
index cf12302d9896978cf459ee5fb54f0e8b560ad3ef..e57a793ff426fbdd458c8ea1e7717a31b2e7ac21 100644 (file)
@@ -12,7 +12,7 @@
        html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(custom_attribute)]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
 #![allow(unused_attributes)]
 
 #[macro_use]
index 7ae4d990c8a4ec469a2ce3da7463343b1ec21119..6cd8e267ec5c114e43742f85195061ca18655901 100644 (file)
@@ -761,17 +761,6 @@ pub fn scalar<C: HasDataLayout>(cx: C, scalar: Scalar) -> Self {
             align,
         }
     }
-
-    pub fn uninhabited(field_count: usize) -> Self {
-        let align = Align::from_bytes(1, 1).unwrap();
-        LayoutDetails {
-            variants: Variants::Single { index: 0 },
-            fields: FieldPlacement::Union(field_count),
-            abi: Abi::Uninhabited,
-            align,
-            size: Size::from_bytes(0)
-        }
-    }
 }
 
 /// The details of the layout of a type, alongside the type itself.
@@ -826,10 +815,10 @@ pub fn is_unsized(&self) -> bool {
     /// Returns true if the type is a ZST and not unsized.
     pub fn is_zst(&self) -> bool {
         match self.abi {
-            Abi::Uninhabited => true,
             Abi::Scalar(_) |
             Abi::ScalarPair(..) |
             Abi::Vector { .. } => false,
+            Abi::Uninhabited => self.size.bytes() == 0,
             Abi::Aggregate { sized } => sized && self.size.bytes() == 0
         }
     }
diff --git a/src/librustc_target/spec/aarch64_unknown_openbsd.rs b/src/librustc_target/spec/aarch64_unknown_openbsd.rs
new file mode 100644 (file)
index 0000000..25817fc
--- /dev/null
@@ -0,0 +1,31 @@
+// 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 spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::openbsd_base::opts();
+    base.max_atomic_width = Some(128);
+    base.abi_blacklist = super::arm_base::abi_blacklist();
+
+    Ok(Target {
+        llvm_target: "aarch64-unknown-openbsd".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        target_os: "openbsd".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
index 79c059c8f952d7884767a7c6eceaf8af396ac52c..f22bf2abe4501f23c30760651c2f67dca6f9cb2c 100644 (file)
@@ -15,6 +15,7 @@ pub fn target() -> TargetResult {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
     base.stack_probes = true;
 
     Ok(Target {
index 293f23eab388317c4b5a5d0bdbd8f50ca3d2426a..4594d450c1507f7a05dbd9078d0f3c9d90dab2c4 100644 (file)
@@ -15,7 +15,8 @@ pub fn opts() -> TargetOptions {
 
     // Make sure that the linker/gcc really don't pull in anything, including
     // default objects, libs, etc.
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
+    base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
+    base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
 
     // At least when this was tested, the linker would not add the
     // `GNU_EH_FRAME` program header to executables generated, which is required
@@ -55,9 +56,11 @@ pub fn opts() -> TargetOptions {
     //
     // Each target directory for musl has these object files included in it so
     // they'll be included from there.
-    base.pre_link_objects_exe.push("crt1.o".to_string());
-    base.pre_link_objects_exe.push("crti.o".to_string());
-    base.post_link_objects.push("crtn.o".to_string());
+    base.pre_link_objects_exe_crt.push("crt1.o".to_string());
+    base.pre_link_objects_exe_crt.push("crti.o".to_string());
+    base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
+    base.post_link_objects_crt_sys.push("crtend.o".to_string());
+    base.post_link_objects_crt.push("crtn.o".to_string());
 
     // These targets statically link libc by default
     base.crt_static_default = true;
index 48e771e0aafab3c942cf8922825cc28cc4276be9..fb20fe9c8918f060aef00931ea6a14dfd07080fb 100644 (file)
@@ -313,6 +313,7 @@ fn $module() {
 
     ("x86_64-unknown-bitrig", x86_64_unknown_bitrig),
 
+    ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
     ("i686-unknown-openbsd", i686_unknown_openbsd),
     ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
 
@@ -421,20 +422,26 @@ pub struct TargetOptions {
     /// Linker to invoke
     pub linker: Option<String>,
 
-    /// Linker arguments that are unconditionally passed *before* any
-    /// user-defined libraries.
-    pub pre_link_args: LinkArgs,
-    /// Objects to link before all others, always found within the
+    /// Linker arguments that are passed *before* any user-defined libraries.
+    pub pre_link_args: LinkArgs, // ... unconditionally
+    pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
+    /// Objects to link before all others, all except *_sys found within the
     /// sysroot folder.
-    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
+    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
+    pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
+    pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
+                                                   //  crt, from the system library search path
     pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post_link_objects.  Standard platform
     /// libraries that should be always be linked to, usually go here.
     pub late_link_args: LinkArgs,
-    /// Objects to link after all others, always found within the
+    /// Objects to link after all others, all except *_sys found within the
     /// sysroot folder.
-    pub post_link_objects: Vec<String>,
+    pub post_link_objects: Vec<String>, // ... unconditionally
+    pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
+    pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
+                                                //  system library search path
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
@@ -634,6 +641,7 @@ fn default() -> TargetOptions {
             is_builtin: false,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             pre_link_args: LinkArgs::new(),
+            pre_link_args_crt: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
             cpu: "generic".to_string(),
@@ -667,8 +675,12 @@ fn default() -> TargetOptions {
             position_independent_executables: false,
             relro_level: RelroLevel::None,
             pre_link_objects_exe: Vec::new(),
+            pre_link_objects_exe_crt: Vec::new(),
+            pre_link_objects_exe_crt_sys: Vec::new(),
             pre_link_objects_dll: Vec::new(),
             post_link_objects: Vec::new(),
+            post_link_objects_crt: Vec::new(),
+            post_link_objects_crt_sys: Vec::new(),
             late_link_args: LinkArgs::new(),
             link_env: Vec::new(),
             archive_format: "gnu".to_string(),
@@ -887,10 +899,15 @@ macro_rules! key {
         key!(is_builtin, bool);
         key!(linker, optional);
         key!(pre_link_args, link_args);
+        key!(pre_link_args_crt, link_args);
         key!(pre_link_objects_exe, list);
+        key!(pre_link_objects_exe_crt, list);
+        key!(pre_link_objects_exe_crt_sys, list);
         key!(pre_link_objects_dll, list);
         key!(late_link_args, link_args);
         key!(post_link_objects, list);
+        key!(post_link_objects_crt, list);
+        key!(post_link_objects_crt_sys, list);
         key!(post_link_args, link_args);
         key!(link_env, env);
         key!(asm_args, list);
@@ -1092,10 +1109,15 @@ macro_rules! target_option_val {
         target_option_val!(is_builtin);
         target_option_val!(linker);
         target_option_val!(link_args - pre_link_args);
+        target_option_val!(link_args - pre_link_args_crt);
         target_option_val!(pre_link_objects_exe);
+        target_option_val!(pre_link_objects_exe_crt);
+        target_option_val!(pre_link_objects_exe_crt_sys);
         target_option_val!(pre_link_objects_dll);
         target_option_val!(link_args - late_link_args);
         target_option_val!(post_link_objects);
+        target_option_val!(post_link_objects_crt);
+        target_option_val!(post_link_objects_crt_sys);
         target_option_val!(link_args - post_link_args);
         target_option_val!(env - link_env);
         target_option_val!(asm_args);
index ce5707276ee1a543a73b96483fd453abec3c5740..219c6b9aefba51f72be5cacf674fcfd98413d0b6 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::traits::query::{CanonicalTyGoal, NoSolution};
 use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{Subst, Substs};
 use rustc::util::nodemap::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use syntax::codemap::{Span, DUMMY_SP};
@@ -278,9 +278,13 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
     debug!("dtorck_constraint: {:?}", def);
 
     if def.is_phantom_data() {
+        // The first generic parameter here is guaranteed to be a type because it's
+        // `PhantomData`.
+        let substs = Substs::identity_for_item(tcx, def_id);
+        assert_eq!(substs.len(), 1);
         let result = DtorckConstraint {
             outlives: vec![],
-            dtorck_types: vec![tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])],
+            dtorck_types: vec![substs.type_at(0)],
             overflows: vec![],
         };
         debug!("dtorck_constraint: {:?} => {:?}", def, result);
index 7f18fac2db5a3a5b8996c722c6959492ac4302c1..f2627f65702411d3e53a0539551c273755c23c39 100644 (file)
@@ -12,6 +12,7 @@
 //! the guts are broken up into modules; see the comments in those modules.
 
 #![feature(crate_visibility_modifier)]
+#![feature(iterator_find_map)]
 
 #[macro_use]
 extern crate log;
index a4dd02e97b233573d417e789950265498e4b4634..64d3a4f4d53be9c0bee5171b0a451d65f5cac42a 100644 (file)
@@ -10,6 +10,7 @@ crate-type = ["dylib"]
 test = false
 
 [dependencies]
+bitflags = "1.0.1"
 cc = "1.0.1"
 flate2 = "1.0"
 jobserver = "0.1.5"
index 1838dae049ad7e1a18cb205ed7ce6648900e4ae0..25c598c532c4897c66d4136c154fa77823ef43bc 100644 (file)
@@ -10,7 +10,7 @@
 
 use llvm::{self, ValueRef, AttributePlace};
 use base;
-use builder::Builder;
+use builder::{Builder, MemFlags};
 use common::{ty_fn_sig, C_usize};
 use context::CodegenCx;
 use mir::place::PlaceRef;
@@ -220,7 +220,8 @@ fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) {
                                   bx.pointercast(dst.llval, Type::i8p(cx)),
                                   bx.pointercast(llscratch, Type::i8p(cx)),
                                   C_usize(cx, self.layout.size.bytes()),
-                                  self.layout.align.min(scratch_align));
+                                  self.layout.align.min(scratch_align),
+                                  MemFlags::empty());
 
                 bx.lifetime_end(llscratch, scratch_size);
             }
index 92f9a9e8ba97464d0a0ef800268bec7fd8ed17f4..299075ed03ad9ec0cfbc922c89f624227f8048fb 100644 (file)
@@ -621,6 +621,11 @@ fn link_natively(sess: &Session,
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
+    if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
+        if sess.crt_static() {
+            cmd.args(args);
+        }
+    }
     if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
         cmd.args(args);
     }
@@ -635,6 +640,18 @@ fn link_natively(sess: &Session,
         cmd.arg(root.join(obj));
     }
 
+    if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+        for obj in &sess.target.target.options.pre_link_objects_exe_crt {
+            cmd.arg(root.join(obj));
+        }
+
+        for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
+            if flavor == LinkerFlavor::Gcc {
+                cmd.arg(format!("-l:{}", obj));
+            }
+        }
+    }
+
     if sess.target.target.options.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -656,6 +673,16 @@ fn link_natively(sess: &Session,
     for obj in &sess.target.target.options.post_link_objects {
         cmd.arg(root.join(obj));
     }
+    if sess.crt_static() {
+        for obj in &sess.target.target.options.post_link_objects_crt_sys {
+            if flavor == LinkerFlavor::Gcc {
+                cmd.arg(format!("-l:{}", obj));
+            }
+        }
+        for obj in &sess.target.target.options.post_link_objects_crt {
+            cmd.arg(root.join(obj));
+        }
+    }
     if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
         cmd.args(args);
     }
@@ -970,6 +997,9 @@ fn link_args(cmd: &mut Linker,
              out_filename: &Path,
              trans: &CrateTranslation) {
 
+    // Linker plugins should be specified early in the list of arguments
+    cmd.cross_lang_lto();
+
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
     let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
index ea3f5b408604ee8f4afa1698589bc3f1b51bcac9..2a84ffe79b285f033711473fb3d5794e60a6ade0 100644 (file)
@@ -21,7 +21,8 @@
 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
 use rustc::middle::dependency_format::Linkage;
 use rustc::session::Session;
-use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
+use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
+                             CrossLangLto};
 use rustc::ty::TyCtxt;
 use rustc_target::spec::{LinkerFlavor, LldFlavor};
 use serialize::{json, Encoder};
@@ -127,6 +128,7 @@ pub trait Linker {
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
     fn group_end(&mut self);
+    fn cross_lang_lto(&mut self);
     // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
     fn finalize(&mut self) -> Command;
 }
@@ -434,6 +436,42 @@ fn group_end(&mut self) {
             self.linker_arg("--end-group");
         }
     }
+
+    fn cross_lang_lto(&mut self) {
+        match self.sess.opts.debugging_opts.cross_lang_lto {
+            CrossLangLto::Disabled |
+            CrossLangLto::NoLink => {
+                // Nothing to do
+            }
+            CrossLangLto::LinkerPlugin(ref path) => {
+                self.linker_arg(&format!("-plugin={}", path.display()));
+
+                let opt_level = match self.sess.opts.optimize {
+                    config::OptLevel::No => "O0",
+                    config::OptLevel::Less => "O1",
+                    config::OptLevel::Default => "O2",
+                    config::OptLevel::Aggressive => "O3",
+                    config::OptLevel::Size => "Os",
+                    config::OptLevel::SizeMin => "Oz",
+                };
+
+                self.linker_arg(&format!("-plugin-opt={}", opt_level));
+                self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
+
+                match self.sess.opts.cg.lto {
+                    config::Lto::Thin |
+                    config::Lto::ThinLocal => {
+                        self.linker_arg(&format!("-plugin-opt=thin"));
+                    }
+                    config::Lto::Fat |
+                    config::Lto::Yes |
+                    config::Lto::No => {
+                        // default to regular LTO
+                    }
+                }
+            }
+        }
+    }
 }
 
 pub struct MsvcLinker<'a> {
@@ -666,6 +704,10 @@ fn finalize(&mut self) -> Command {
     // MSVC doesn't need group indicators
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing
+    }
 }
 
 pub struct EmLinker<'a> {
@@ -832,6 +874,10 @@ fn finalize(&mut self) -> Command {
     // Appears not necessary on Emscripten
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing
+    }
 }
 
 fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
@@ -984,4 +1030,8 @@ fn finalize(&mut self) -> Command {
     // Not needed for now with LLD
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing for now
+    }
 }
index 2a473f1ecbcc5efcff393a10b751c22a0ae96998..bbb5f7eecc82c28223cd4e6edad47cca48769d17 100644 (file)
@@ -482,7 +482,7 @@ fn run_pass_manager(cgcx: &CodegenContext,
             llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
             level => level,
         };
-        with_llvm_pmb(llmod, config, opt_level, &mut |b| {
+        with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
             if thin {
                 if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
                     panic!("this version of LLVM does not support ThinLTO");
index d8520b61d9157b624e6c0917a08a51a5d676504a..d77855220691d31113a8ef018b636552baf1e02e 100644 (file)
@@ -117,7 +117,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }) => {
                     let def_id = tcx.hir.local_def_id(node_id);
                     let generics = tcx.generics_of(def_id);
-                    if (generics.parent_types == 0 && generics.types.is_empty()) &&
+                    if !generics.requires_monomorphization(tcx) &&
                         // Functions marked with #[inline] are only ever translated
                         // with "internal" linkage and are never exported.
                         !Instance::mono(tcx, def_id).def.requires_local(tcx) {
index b6fae3eaff23a64cfd0cf62f5a207790562d76e8..acfe7c33028274a1be426816e9dd3f19f2545693 100644 (file)
@@ -17,8 +17,8 @@
 use back::symbol_export::ExportedSymbols;
 use base;
 use consts;
-use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use rustc::dep_graph::{DepGraph, WorkProductFileKind};
+use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
                              AllPasses, Sanitizer, Lto};
@@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
     let triple = &sess.target.target.llvm_target;
 
     let triple = CString::new(triple.as_bytes()).unwrap();
-    let cpu = match sess.opts.cg.target_cpu {
-        Some(ref s) => &**s,
-        None => &*sess.target.target.options.cpu
-    };
+    let cpu = sess.target_cpu();
     let cpu = CString::new(cpu.as_bytes()).unwrap();
     let features = attributes::llvm_target_features(sess)
         .collect::<Vec<_>>()
@@ -294,7 +291,7 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
         self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
         let embed_bitcode = sess.target.target.options.embed_bitcode ||
                             sess.opts.debugging_opts.embed_bitcode ||
-                            sess.opts.debugging_opts.cross_lang_lto;
+                            sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
         if embed_bitcode {
             match sess.opts.optimize {
                 config::OptLevel::No |
@@ -550,7 +547,8 @@ unsafe fn optimize(cgcx: &CodegenContext,
             llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
             llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
             let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
-            with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
+            let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
+            with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
                 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
                 llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
             })
@@ -1024,11 +1022,14 @@ pub fn start_async_translation(tcx: TyCtxt,
     }
 }
 
-fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
-                                              dep_graph: &DepGraph,
-                                              compiled_modules: &CompiledModules) {
+fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
+    sess: &Session,
+    compiled_modules: &CompiledModules
+) -> FxHashMap<WorkProductId, WorkProduct> {
+    let mut work_products = FxHashMap::default();
+
     if sess.opts.incremental.is_none() {
-        return;
+        return work_products;
     }
 
     for module in compiled_modules.modules.iter() {
@@ -1044,8 +1045,13 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
             files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
         }
 
-        save_trans_partition(sess, dep_graph, &module.name, &files);
+        if let Some((id, product)) =
+                copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+            work_products.insert(id, product);
+        }
     }
+
+    work_products
 }
 
 fn produce_final_output_artifacts(sess: &Session,
@@ -1358,7 +1364,8 @@ fn execute_work_item(cgcx: &CodegenContext,
 
             // Don't run LTO passes when cross-lang LTO is enabled. The linker
             // will do that for us in this case.
-            let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
+            let needs_lto = needs_lto &&
+                !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
 
             if needs_lto {
                 Ok(WorkItemResult::NeedsLTO(mtrans))
@@ -2044,6 +2051,7 @@ pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path,
 pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
                             config: &ModuleConfig,
                             opt_level: llvm::CodeGenOptLevel,
+                            prepare_for_thin_lto: bool,
                             f: &mut FnMut(llvm::PassManagerBuilderRef)) {
     use std::ptr;
 
@@ -2071,6 +2079,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
         config.merge_functions,
         config.vectorize_slp,
         config.vectorize_loop,
+        prepare_for_thin_lto,
         pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
         pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
     );
@@ -2238,7 +2247,10 @@ pub struct OngoingCrateTranslation {
 }
 
 impl OngoingCrateTranslation {
-    pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
+    pub(crate) fn join(
+        self,
+        sess: &Session
+    ) -> (CrateTranslation, FxHashMap<WorkProductId, WorkProduct>) {
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = match self.future.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
@@ -2257,9 +2269,9 @@ pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslati
             time_graph.dump(&format!("{}-timings", self.crate_name));
         }
 
-        copy_module_artifacts_into_incr_comp_cache(sess,
-                                                   dep_graph,
-                                                   &compiled_modules);
+        let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
+                                                                             &compiled_modules);
+
         produce_final_output_artifacts(sess,
                                        &compiled_modules,
                                        &self.output_filenames);
@@ -2283,7 +2295,7 @@ pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslati
             metadata_module: compiled_modules.metadata_module,
         };
 
-        trans
+        (trans, work_products)
     }
 
     pub(crate) fn submit_pre_translated_module_to_llvm(&self,
index 33dc9b3b7ab90087caf3291f7c1ae6aabe53115d..feca36fa6c24355d8f80fee4aa5258ccd294be7a 100644 (file)
@@ -53,7 +53,7 @@
 use allocator;
 use mir::place::PlaceRef;
 use attributes;
-use builder::Builder;
+use builder::{Builder, MemFlags};
 use callee;
 use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
 use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
@@ -199,7 +199,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
     let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
         (&ty::TyArray(_, len), &ty::TySlice(_)) => {
-            C_usize(cx, len.val.unwrap_u64())
+            C_usize(cx, len.unwrap_usize(cx.tcx))
         }
         (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
@@ -320,7 +320,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
 
                 if src_f.layout.ty == dst_f.layout.ty {
                     memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
-                        src_f.align.min(dst_f.align));
+                              src_f.align.min(dst_f.align), MemFlags::empty());
                 } else {
                     coerce_unsized_into(bx, src_f, dst_f);
                 }
@@ -408,7 +408,15 @@ pub fn call_memcpy(bx: &Builder,
                    dst: ValueRef,
                    src: ValueRef,
                    n_bytes: ValueRef,
-                   align: Align) {
+                   align: Align,
+                   flags: MemFlags) {
+    if flags.contains(MemFlags::NONTEMPORAL) {
+        // HACK(nox): This is inefficient but there is no nontemporal memcpy.
+        let val = bx.load(src, align);
+        let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
+        bx.store_with_flags(val, ptr, align, flags);
+        return;
+    }
     let cx = bx.cx;
     let ptr_width = &cx.sess().target.target.target_pointer_width;
     let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
@@ -417,7 +425,7 @@ pub fn call_memcpy(bx: &Builder,
     let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
     let size = bx.intcast(n_bytes, cx.isize_ty, false);
     let align = C_i32(cx, align.abi() as i32);
-    let volatile = C_bool(cx, false);
+    let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
     bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
 }
 
@@ -427,13 +435,14 @@ pub fn memcpy_ty<'a, 'tcx>(
     src: ValueRef,
     layout: TyLayout<'tcx>,
     align: Align,
+    flags: MemFlags,
 ) {
     let size = layout.size.bytes();
     if size == 0 {
         return;
     }
 
-    call_memcpy(bx, dst, src, C_usize(bx.cx, size), align);
+    call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
 }
 
 pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
@@ -1372,7 +1381,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 }
 
 fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
-    use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+    use rustc::mir::interpret::GlobalId;
     use rustc::middle::const_val::ConstVal;
 
     info!("loading wasm section {:?}", id);
@@ -1392,22 +1401,11 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
     let param_env = ty::ParamEnv::reveal_all();
     let val = tcx.const_eval(param_env.and(cid)).unwrap();
 
-    let val = match val.val {
+    let const_val = match val.val {
         ConstVal::Value(val) => val,
         ConstVal::Unevaluated(..) => bug!("should be evaluated"),
     };
-    let val = match val {
-        Value::ByRef(ptr, _align) => ptr.into_inner_primval(),
-        ref v => bug!("should be ByRef, was {:?}", v),
-    };
-    let mem = match val {
-        PrimVal::Ptr(mem) => mem,
-        ref v => bug!("should be Ptr, was {:?}", v),
-    };
-    assert_eq!(mem.offset, 0);
-    let alloc = tcx
-        .interpret_interner
-        .get_alloc(mem.alloc_id)
-        .expect("miri allocation never successfully created");
+
+    let alloc = tcx.const_value_to_allocation((const_val, val.ty));
     (section.to_string(), alloc.bytes.clone())
 }
index db803ca8209d9c67870e9bd5da01d1e19b9450b9..4153c61e5269a0af6421794ef958de83968b761f 100644 (file)
@@ -50,6 +50,13 @@ fn noname() -> *const c_char {
     &CNULL
 }
 
+bitflags! {
+    pub struct MemFlags: u8 {
+        const VOLATILE = 1 << 0;
+        const NONTEMPORAL = 1 << 1;
+    }
+}
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self {
         let bx = Builder::with_cx(cx);
@@ -579,29 +586,39 @@ pub fn nonnull_metadata(&self, load: ValueRef) {
     }
 
     pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef {
-        debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
+        self.store_with_flags(val, ptr, align, MemFlags::empty())
+    }
+
+    pub fn store_with_flags(
+        &self,
+        val: ValueRef,
+        ptr: ValueRef,
+        align: Align,
+        flags: MemFlags,
+    ) -> ValueRef {
+        debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags);
         assert!(!self.llbuilder.is_null());
         self.count_insn("store");
         let ptr = self.check_store(val, ptr);
         unsafe {
             let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
             llvm::LLVMSetAlignment(store, align.abi() as c_uint);
+            if flags.contains(MemFlags::VOLATILE) {
+                llvm::LLVMSetVolatile(store, llvm::True);
+            }
+            if flags.contains(MemFlags::NONTEMPORAL) {
+                // According to LLVM [1] building a nontemporal store must
+                // *always* point to a metadata value of the integer 1.
+                //
+                // [1]: http://llvm.org/docs/LangRef.html#store-instruction
+                let one = C_i32(self.cx, 1);
+                let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
+                llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+            }
             store
         }
     }
 
-    pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
-        debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
-        assert!(!self.llbuilder.is_null());
-        self.count_insn("store.volatile");
-        let ptr = self.check_store(val, ptr);
-        unsafe {
-            let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
-            llvm::LLVMSetVolatile(insn, llvm::True);
-            insn
-        }
-    }
-
     pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
                         order: AtomicOrdering, align: Align) {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
@@ -615,29 +632,6 @@ pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
         }
     }
 
-    pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
-        debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
-        assert!(!self.llbuilder.is_null());
-        self.count_insn("store.nontemporal");
-        let ptr = self.check_store(val, ptr);
-        unsafe {
-            let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
-
-            // According to LLVM [1] building a nontemporal store must *always*
-            // point to a metadata value of the integer 1. Who knew?
-            //
-            // [1]: http://llvm.org/docs/LangRef.html#store-instruction
-            let one = C_i32(self.cx, 1);
-            let node = llvm::LLVMMDNodeInContext(self.cx.llcx,
-                                                 &one,
-                                                 1);
-            llvm::LLVMSetMetadata(insn,
-                                  llvm::MD_nontemporal as c_uint,
-                                  node);
-            insn
-        }
-    }
-
     pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
         self.count_insn("gep");
         unsafe {
index ae23b523cbfaebcb68fa9dc4e56e44a2a5d2a297..4e77c0df65ef4eeeb6569d2d67b0f237c1d4ca8d 100644 (file)
@@ -277,7 +277,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
     let upper_bound = match array_or_slice_type.sty {
         ty::TyArray(_, len) => {
-            len.val.unwrap_u64() as c_longlong
+            len.unwrap_usize(cx.tcx) as c_longlong
         }
         _ => -1
     };
index 30676b91620a62c27e7d60e03bbcfcd6f7a114f3..2039a90a043bf4c5fd9a5240ddad9505fbe35c65 100644 (file)
@@ -25,7 +25,7 @@
 use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
 use rustc::hir::TransFnAttrFlags;
 use rustc::hir::def_id::{DefId, CrateNum};
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, UnpackedKind};
 
 use abi::Abi;
 use common::CodegenCx;
@@ -390,20 +390,25 @@ fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
         // Again, only create type information if full debuginfo is enabled
         let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
-            let names = get_type_parameter_names(cx, generics);
-            substs.types().zip(names).map(|(ty, name)| {
-                let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
-                let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
-                let name = CString::new(name.as_str().as_bytes()).unwrap();
-                unsafe {
-                    llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
-                        DIB(cx),
-                        ptr::null_mut(),
-                        name.as_ptr(),
-                        actual_type_metadata,
-                        file_metadata,
-                        0,
-                        0)
+            let names = get_parameter_names(cx, generics);
+            substs.iter().zip(names).filter_map(|(kind, name)| {
+                if let UnpackedKind::Type(ty) = kind.unpack() {
+                    let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+                    let actual_type_metadata =
+                        type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
+                    let name = CString::new(name.as_str().as_bytes()).unwrap();
+                    Some(unsafe {
+                        llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+                            DIB(cx),
+                            ptr::null_mut(),
+                            name.as_ptr(),
+                            actual_type_metadata,
+                            file_metadata,
+                            0,
+                            0)
+                    })
+                } else {
+                    None
                 }
             }).collect()
         } else {
@@ -413,11 +418,13 @@ fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         return create_DIArray(DIB(cx), &template_params[..]);
     }
 
-    fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<InternedString> {
+    fn get_parameter_names(cx: &CodegenCx,
+                           generics: &ty::Generics)
+                           -> Vec<InternedString> {
         let mut names = generics.parent.map_or(vec![], |def_id| {
-            get_type_parameter_names(cx, cx.tcx.generics_of(def_id))
+            get_parameter_names(cx, cx.tcx.generics_of(def_id))
         });
-        names.extend(generics.types.iter().map(|param| param.name));
+        names.extend(generics.params.iter().map(|param| param.name));
         names
     }
 
index 565a9bedef0f51d724bf78e044bcb1e7c66891b0..05a74db3a6ca9842470d51991fc589dc5998c88a 100644 (file)
@@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::TyArray(inner_type, len) => {
             output.push('[');
             push_debuginfo_type_name(cx, inner_type, true, output);
-            output.push_str(&format!("; {}", len.val.unwrap_u64()));
+            output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
             output.push(']');
         },
         ty::TySlice(inner_type) => {
index 49a207a2d8ab5b299f54812d1c45ea0bcf879fd2..86aa48b6a9e4801085f055240956d31dae7160ad 100644 (file)
@@ -247,26 +247,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
             to_immediate(bx, load, cx.layout_of(tp_ty))
         },
         "volatile_store" => {
-            let tp_ty = substs.type_at(0);
             let dst = args[0].deref(bx.cx);
-            if let OperandValue::Pair(a, b) = args[1].val {
-                bx.volatile_store(a, dst.project_field(bx, 0).llval);
-                bx.volatile_store(b, dst.project_field(bx, 1).llval);
-            } else {
-                let val = if let OperandValue::Ref(ptr, align) = args[1].val {
-                    bx.load(ptr, align)
-                } else {
-                    if dst.layout.is_zst() {
-                        return;
-                    }
-                    from_immediate(bx, args[1].immediate())
-                };
-                let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to());
-                let store = bx.volatile_store(val, ptr);
-                unsafe {
-                    llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32);
-                }
-            }
+            args[1].val.volatile_store(bx, dst);
             return;
         },
         "prefetch_read_data" | "prefetch_write_data" |
@@ -551,19 +533,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
         }
 
         "nontemporal_store" => {
-            let tp_ty = substs.type_at(0);
             let dst = args[0].deref(bx.cx);
-            let val = if let OperandValue::Ref(ptr, align) = args[1].val {
-                bx.load(ptr, align)
-            } else {
-                from_immediate(bx, args[1].immediate())
-            };
-            let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to());
-            let store = bx.nontemporal_store(val, ptr);
-            unsafe {
-                llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32);
-            }
-            return
+            args[1].val.nontemporal_store(bx, dst);
+            return;
         }
 
         _ => {
index 7a152d6ded4c56ecc957f4d6ce7c40d5a1a31c31..6db95657ce058a95fca93d7d8ecbf6f508f241dc 100644 (file)
@@ -34,6 +34,7 @@
 use rustc::dep_graph::WorkProduct;
 use syntax_pos::symbol::Symbol;
 
+#[macro_use] extern crate bitflags;
 extern crate flate2;
 extern crate libc;
 #[macro_use] extern crate rustc;
@@ -212,16 +213,16 @@ fn join_trans_and_link(
         outputs: &OutputFilenames,
     ) -> Result<(), CompileIncomplete>{
         use rustc::util::common::time;
-        let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+        let (trans, work_products) = trans.downcast::<::back::write::OngoingCrateTranslation>()
             .expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
-            .join(sess, dep_graph);
+            .join(sess);
         if sess.opts.debugging_opts.incremental_info {
             back::write::dump_incremental_data(&trans);
         }
 
         time(sess,
              "serialize work products",
-             move || rustc_incremental::save_work_products(sess, &dep_graph));
+             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));
 
         sess.compile_status()?;
 
index b666c2b211525713e762126a5a437160a7ca787b..e4989da36c02673c4bbaec777197eddb2adc671f 100644 (file)
@@ -17,7 +17,7 @@
 use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode};
 use base;
 use callee;
-use builder::Builder;
+use builder::{Builder, MemFlags};
 use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef};
 use consts;
 use meth;
@@ -626,7 +626,7 @@ fn trans_argument(&mut self,
                     // have scary latent bugs around.
 
                     let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
-                    base::memcpy_ty(bx, scratch.llval, llval, op.layout, align);
+                    base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty());
                     (scratch.llval, scratch.align, true)
                 } else {
                     (llval, align, true)
index 6e07b8e73ef22c329ea9c8749ede3d649ae14667..a10b7c9c9f10f23a818d98dd2b8ead0e96fd3fb5 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
 use builder::Builder;
@@ -56,7 +56,7 @@ pub fn primval_to_llvm(cx: &CodegenCx,
                     consts::get_static(cx, def_id)
                 } else if let Some(alloc) = cx.tcx.interpret_interner
                                               .get_alloc(ptr.alloc_id) {
-                    let init = global_initializer(cx, alloc);
+                    let init = const_alloc_to_llvm(cx, alloc);
                     if alloc.runtime_mutability == Mutability::Mutable {
                         consts::addr_of_mut(cx, init, alloc.align, "byte_str")
                     } else {
@@ -81,7 +81,50 @@ pub fn primval_to_llvm(cx: &CodegenCx,
     }
 }
 
-pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
+    let layout = cx.layout_of(ty);
+
+    if layout.is_zst() {
+        return C_undef(layout.immediate_llvm_type(cx));
+    }
+
+    match val {
+        ConstValue::ByVal(x) => {
+            let scalar = match layout.abi {
+                layout::Abi::Scalar(ref x) => x,
+                _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
+            };
+            primval_to_llvm(
+                cx,
+                x,
+                scalar,
+                layout.immediate_llvm_type(cx),
+            )
+        },
+        ConstValue::ByValPair(a, b) => {
+            let (a_scalar, b_scalar) = match layout.abi {
+                layout::Abi::ScalarPair(ref a, ref b) => (a, b),
+                _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
+            };
+            let a_llval = primval_to_llvm(
+                cx,
+                a,
+                a_scalar,
+                layout.scalar_pair_element_llvm_type(cx, 0),
+            );
+            let b_llval = primval_to_llvm(
+                cx,
+                b,
+                b_scalar,
+                layout.scalar_pair_element_llvm_type(cx, 1),
+            );
+            C_struct(cx, &[a_llval, b_llval], false)
+        },
+        ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
+    }
+}
+
+pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
     let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
     let layout = cx.data_layout();
     let pointer_size = layout.pointer_size.bytes() as usize;
@@ -96,7 +139,7 @@ pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
         let ptr_offset = read_target_uint(
             layout.endian,
             &alloc.bytes[offset..(offset + pointer_size)],
-        ).expect("global_initializer: could not read relocation pointer") as u64;
+        ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
         llvals.push(primval_to_llvm(
             cx,
             PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
@@ -128,25 +171,19 @@ pub fn trans_static_initializer<'a, 'tcx>(
     let param_env = ty::ParamEnv::reveal_all();
     let static_ = cx.tcx.const_eval(param_env.and(cid))?;
 
-    let ptr = match static_.val {
-        ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr,
+    let val = match static_.val {
+        ConstVal::Value(val) => val,
         _ => bug!("static const eval returned {:#?}", static_),
     };
-
-    let alloc = cx
-        .tcx
-        .interpret_interner
-        .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id)
-        .expect("miri allocation never successfully created");
-    Ok(global_initializer(cx, alloc))
+    Ok(const_value_to_llvm(cx, val, static_.ty))
 }
 
 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
-    fn const_to_miri_value(
+    fn const_to_const_value(
         &mut self,
         bx: &Builder<'a, 'tcx>,
         constant: &'tcx ty::Const<'tcx>,
-    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+    ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
         match constant.val {
             ConstVal::Unevaluated(def_id, ref substs) => {
                 let tcx = bx.tcx();
@@ -157,17 +194,17 @@ fn const_to_miri_value(
                     promoted: None,
                 };
                 let c = tcx.const_eval(param_env.and(cid))?;
-                self.const_to_miri_value(bx, c)
+                self.const_to_const_value(bx, c)
             },
-            ConstVal::Value(miri_val) => Ok(miri_val),
+            ConstVal::Value(val) => Ok(val),
         }
     }
 
-    pub fn mir_constant_to_miri_value(
+    pub fn mir_constant_to_const_value(
         &mut self,
         bx: &Builder<'a, 'tcx>,
         constant: &mir::Constant<'tcx>,
-    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+    ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
         match constant.literal {
             mir::Literal::Promoted { index } => {
                 let param_env = ty::ParamEnv::reveal_all();
@@ -180,7 +217,7 @@ pub fn mir_constant_to_miri_value(
             mir::Literal::Value { value } => {
                 Ok(self.monomorphize(&value))
             }
-        }.and_then(|c| self.const_to_miri_value(bx, c))
+        }.and_then(|c| self.const_to_const_value(bx, c))
     }
 
     /// process constant containing SIMD shuffle indices
@@ -189,11 +226,11 @@ pub fn simd_shuffle_indices(
         bx: &Builder<'a, 'tcx>,
         constant: &mir::Constant<'tcx>,
     ) -> (ValueRef, Ty<'tcx>) {
-        self.mir_constant_to_miri_value(bx, constant)
+        self.mir_constant_to_const_value(bx, constant)
             .and_then(|c| {
                 let field_ty = constant.ty.builtin_index().unwrap();
                 let fields = match constant.ty.sty {
-                    ty::TyArray(_, n) => n.val.unwrap_u64(),
+                    ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
                     ref other => bug!("invalid simd shuffle type: {}", other),
                 };
                 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
@@ -206,19 +243,18 @@ pub fn simd_shuffle_indices(
                         c,
                         constant.ty,
                     )?;
-                    match field.val {
-                        ConstVal::Value(MiriValue::ByVal(prim)) => {
-                            let layout = bx.cx.layout_of(field_ty);
-                            let scalar = match layout.abi {
-                                layout::Abi::Scalar(ref x) => x,
-                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
-                            };
-                            Ok(primval_to_llvm(
-                                bx.cx, prim, scalar,
-                                layout.immediate_llvm_type(bx.cx),
-                            ))
-                        },
-                        other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+                    if let Some(prim) = field.to_primval() {
+                        let layout = bx.cx.layout_of(field_ty);
+                        let scalar = match layout.abi {
+                            layout::Abi::Scalar(ref x) => x,
+                            _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                        };
+                        Ok(primval_to_llvm(
+                            bx.cx, prim, scalar,
+                            layout.immediate_llvm_type(bx.cx),
+                        ))
+                    } else {
+                        bug!("simd shuffle field {:?}", field)
                     }
                 }).collect();
                 let llval = C_struct(bx.cx, &values?, false);
index 656ab95a28cf3e1730c78092260dc9ec40e9fb90..be14da1a195bf07b8c9a333e60061ba66b2d41d4 100644 (file)
 use llvm::ValueRef;
 use rustc::middle::const_val::ConstEvalErr;
 use rustc::mir;
-use rustc::mir::interpret::Value as MiriValue;
+use rustc::mir::interpret::ConstValue;
 use rustc::ty;
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
 use base;
 use common::{self, CodegenCx, C_null, C_undef, C_usize};
-use builder::Builder;
+use builder::{Builder, MemFlags};
 use value::Value;
 use type_of::LayoutLlvmExt;
 use type_::Type;
+use consts;
 
 use std::fmt;
 use std::ptr;
 
 use super::{FunctionCx, LocalRef};
-use super::constant::{primval_to_llvm};
+use super::constant::{primval_to_llvm, const_alloc_to_llvm};
 use super::place::PlaceRef;
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -94,7 +95,7 @@ pub fn new_zst(cx: &CodegenCx<'a, 'tcx>,
     }
 
     pub fn from_const(bx: &Builder<'a, 'tcx>,
-                      miri_val: MiriValue,
+                      val: ConstValue<'tcx>,
                       ty: ty::Ty<'tcx>)
                       -> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
         let layout = bx.cx.layout_of(ty);
@@ -103,8 +104,8 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
             return Ok(OperandRef::new_zst(bx.cx, layout));
         }
 
-        let val = match miri_val {
-            MiriValue::ByVal(x) => {
+        let val = match val {
+            ConstValue::ByVal(x) => {
                 let scalar = match layout.abi {
                     layout::Abi::Scalar(ref x) => x,
                     _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
@@ -117,7 +118,7 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
                 );
                 OperandValue::Immediate(llval)
             },
-            MiriValue::ByValPair(a, b) => {
+            ConstValue::ByValPair(a, b) => {
                 let (a_scalar, b_scalar) = match layout.abi {
                     layout::Abi::ScalarPair(ref a, ref b) => (a, b),
                     _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
@@ -136,18 +137,11 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
                 );
                 OperandValue::Pair(a_llval, b_llval)
             },
-            MiriValue::ByRef(ptr, align) => {
-                let scalar = layout::Scalar {
-                    value: layout::Primitive::Pointer,
-                    valid_range: 0..=!0
-                };
-                let ptr = primval_to_llvm(
-                    bx.cx,
-                    ptr.into_inner_primval(),
-                    &scalar,
-                    layout.llvm_type(bx.cx).ptr_to(),
-                );
-                return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
+            ConstValue::ByRef(alloc) => {
+                let init = const_alloc_to_llvm(bx.cx, alloc);
+                let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+                let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
+                return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
             },
         };
 
@@ -223,12 +217,9 @@ pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx
         let offset = self.layout.fields.offset(i);
 
         let mut val = match (self.val, &self.layout.abi) {
-            // If we're uninhabited, or the field is ZST, it has no data.
-            _ if self.layout.abi == layout::Abi::Uninhabited || field.is_zst() => {
-                return OperandRef {
-                    val: OperandValue::Immediate(C_undef(field.immediate_llvm_type(bx.cx))),
-                    layout: field
-                };
+            // If the field is ZST, it has no data.
+            _ if field.is_zst() => {
+                return OperandRef::new_zst(bx.cx, field);
             }
 
             // Newtype of a scalar, scalar pair or vector.
@@ -281,6 +272,18 @@ pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx
 
 impl<'a, 'tcx> OperandValue {
     pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+        self.store_with_flags(bx, dest, MemFlags::empty());
+    }
+
+    pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+        self.store_with_flags(bx, dest, MemFlags::VOLATILE);
+    }
+
+    pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+        self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
+    }
+
+    fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) {
         debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
         // value is through `undef`, and store itself is useless.
@@ -288,11 +291,13 @@ pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
             return;
         }
         match self {
-            OperandValue::Ref(r, source_align) =>
+            OperandValue::Ref(r, source_align) => {
                 base::memcpy_ty(bx, dest.llval, r, dest.layout,
-                                source_align.min(dest.align)),
+                                source_align.min(dest.align), flags)
+            }
             OperandValue::Immediate(s) => {
-                bx.store(base::from_immediate(bx, s), dest.llval, dest.align);
+                let val = base::from_immediate(bx, s);
+                bx.store_with_flags(val, dest.llval, dest.align, flags);
             }
             OperandValue::Pair(a, b) => {
                 for (i, &x) in [a, b].iter().enumerate() {
@@ -301,7 +306,8 @@ pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
                     if common::val_ty(x) == Type::i1(bx.cx) {
                         llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
                     }
-                    bx.store(base::from_immediate(bx, x), llptr, dest.align);
+                    let val = base::from_immediate(bx, x);
+                    bx.store_with_flags(val, llptr, dest.align, flags);
                 }
             }
         }
@@ -396,7 +402,7 @@ pub fn trans_operand(&mut self,
 
             mir::Operand::Constant(ref constant) => {
                 let ty = self.monomorphize(&constant.ty);
-                self.mir_constant_to_miri_value(bx, constant)
+                self.mir_constant_to_const_value(bx, constant)
                     .and_then(|c| OperandRef::from_const(bx, c, ty))
                     .unwrap_or_else(|err| {
                         match constant.literal {
index 0cd823391b9b66ed4dd6872afb2f56d6ce51f0bc..3b4477564502c4f11f17e8b6a26af70e5585c7f9 100644 (file)
@@ -516,7 +516,7 @@ fn evaluate_array_len(&mut self,
         if let mir::Place::Local(index) = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::TyArray(_, n) = op.layout.ty.sty {
-                    let n = n.val.unwrap_u64();
+                    let n = n.unwrap_usize(bx.cx.tcx);
                     return common::C_usize(bx.cx, n);
                 }
             }
index f736e81202a38c92b32df094c1991599fe74b711..32d26052aff5dd7ad36a0a634d020776b93541fe 100644 (file)
@@ -213,10 +213,10 @@ fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
 impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
     fn is_llvm_immediate(&self) -> bool {
         match self.abi {
-            layout::Abi::Uninhabited |
             layout::Abi::Scalar(_) |
             layout::Abi::Vector { .. } => true,
             layout::Abi::ScalarPair(..) => false,
+            layout::Abi::Uninhabited |
             layout::Abi::Aggregate { .. } => self.is_zst()
         }
     }
index 93dbba6e873a9d4f807e906dfd8008c2f1335a93..c1868467503f823d0d17fed9d202de43c73d0873 100644 (file)
@@ -12,7 +12,6 @@
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
 
-use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use hir;
 use hir::def::Def;
@@ -22,6 +21,7 @@
 use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
 use rustc::ty::wf::object_region_bounds;
 use rustc_target::spec::abi;
 use std::slice;
@@ -44,7 +44,7 @@ fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
                                  -> ty::GenericPredicates<'tcx>;
 
     /// What lifetime should we use when a lifetime is omitted (and not elided)?
-    fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
+    fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
                 -> Option<ty::Region<'tcx>>;
 
     /// What type should we use when a type is omitted?
@@ -52,7 +52,7 @@ fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
 
     /// Same as ty_infer, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
-                        _def: &ty::TypeParameterDef,
+                        _def: &ty::GenericParamDef,
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
     }
@@ -88,6 +88,11 @@ struct ConvertedBinding<'tcx> {
     span: Span,
 }
 
+struct ParamRange {
+    required: usize,
+    accepted: usize
+}
+
 /// Dummy type used for the `Self` of a `TraitRef` created for converting
 /// a trait object, and which gets removed in `ExistentialTraitRef`.
 /// This type must not appear anywhere in other converted types.
@@ -96,7 +101,7 @@ struct ConvertedBinding<'tcx> {
 impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     pub fn ast_region_to_region(&self,
         lifetime: &hir::Lifetime,
-        def: Option<&ty::RegionParameterDef>)
+        def: Option<&ty::GenericParamDef>)
         -> ty::Region<'tcx>
     {
         let tcx = self.tcx();
@@ -209,92 +214,119 @@ fn create_substs_for_ast_path(&self,
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
         let decl_generics = tcx.generics_of(def_id);
-        let num_types_provided = parameters.types.len();
-        let expected_num_region_params = decl_generics.regions.len();
-        let supplied_num_region_params = parameters.lifetimes.len();
-        if expected_num_region_params != supplied_num_region_params {
-            report_lifetime_number_error(tcx, span,
-                                         supplied_num_region_params,
-                                         expected_num_region_params);
+        let ty_provided = parameters.types.len();
+        let lt_provided = parameters.lifetimes.len();
+
+        let mut lt_accepted = 0;
+        let mut ty_params = ParamRange { required: 0, accepted: 0 };
+        for param in &decl_generics.params {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    lt_accepted += 1;
+                }
+                GenericParamDefKind::Type(ty) => {
+                    ty_params.accepted += 1;
+                    if !ty.has_default {
+                        ty_params.required += 1;
+                    }
+                }
+            };
+        }
+        if self_ty.is_some() {
+            ty_params.required -= 1;
+            ty_params.accepted -= 1;
+        }
+
+        if lt_accepted != lt_provided {
+            report_lifetime_number_error(tcx, span, lt_provided, lt_accepted);
         }
 
         // If a self-type was declared, one should be provided.
         assert_eq!(decl_generics.has_self, self_ty.is_some());
 
         // Check the number of type parameters supplied by the user.
-        let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..];
-        if !infer_types || num_types_provided > ty_param_defs.len() {
-            check_type_argument_count(tcx, span, num_types_provided, ty_param_defs);
+        if !infer_types || ty_provided > ty_params.required {
+            check_type_argument_count(tcx, span, ty_provided, ty_params);
         }
 
         let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
-        let default_needs_object_self = |p: &ty::TypeParameterDef| {
-            if is_object && p.has_default {
-                if tcx.at(span).type_of(p.def_id).has_self_ty() {
-                    // There is no suitable inference default for a type parameter
-                    // that references self, in an object type.
-                    return true;
+        let default_needs_object_self = |param: &ty::GenericParamDef| {
+            if let GenericParamDefKind::Type(ty) = param.kind {
+                if is_object && ty.has_default {
+                    if tcx.at(span).type_of(param.def_id).has_self_ty() {
+                        // There is no suitable inference default for a type parameter
+                        // that references self, in an object type.
+                        return true;
+                    }
                 }
             }
 
             false
         };
 
-        let substs = Substs::for_item(tcx, def_id, |def, _| {
-            let i = def.index as usize - self_ty.is_some() as usize;
-            if let Some(lifetime) = parameters.lifetimes.get(i) {
-                self.ast_region_to_region(lifetime, Some(def))
-            } else {
-                tcx.types.re_static
-            }
-        }, |def, substs| {
-            let i = def.index as usize;
+        let own_self = self_ty.is_some() as usize;
+        let substs = Substs::for_item(tcx, def_id, |param, substs| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    let i = param.index as usize - own_self;
+                    if let Some(lifetime) = parameters.lifetimes.get(i) {
+                        self.ast_region_to_region(lifetime, Some(param)).into()
+                    } else {
+                        tcx.types.re_static.into()
+                    }
+                }
+                GenericParamDefKind::Type(ty) => {
+                    let i = param.index as usize;
 
-            // Handle Self first, so we can adjust the index to match the AST.
-            if let (0, Some(ty)) = (i, self_ty) {
-                return ty;
-            }
+                    // Handle Self first, so we can adjust the index to match the AST.
+                    if let (0, Some(ty)) = (i, self_ty) {
+                        return ty.into();
+                    }
 
-            let i = i - self_ty.is_some() as usize - decl_generics.regions.len();
-            if i < num_types_provided {
-                // A provided type parameter.
-                self.ast_ty_to_ty(&parameters.types[i])
-            } else if infer_types {
-                // No type parameters were provided, we can infer all.
-                let ty_var = if !default_needs_object_self(def) {
-                    self.ty_infer_for_def(def, span)
-                } else {
-                    self.ty_infer(span)
-                };
-                ty_var
-            } else if def.has_default {
-                // No type parameter provided, but a default exists.
-
-                // If we are converting an object type, then the
-                // `Self` parameter is unknown. However, some of the
-                // other type parameters may reference `Self` in their
-                // defaults. This will lead to an ICE if we are not
-                // careful!
-                if default_needs_object_self(def) {
-                    struct_span_err!(tcx.sess, span, E0393,
-                                     "the type parameter `{}` must be explicitly specified",
-                                     def.name)
-                        .span_label(span, format!("missing reference to `{}`", def.name))
-                        .note(&format!("because of the default `Self` reference, \
-                                        type parameters must be specified on object types"))
-                        .emit();
-                    tcx.types.err
-                } else {
-                    // This is a default type parameter.
-                    self.normalize_ty(
-                        span,
-                        tcx.at(span).type_of(def.def_id)
-                            .subst_spanned(tcx, substs, Some(span))
-                    )
+                    let i = i - (lt_accepted + own_self);
+                    if i < ty_provided {
+                        // A provided type parameter.
+                        self.ast_ty_to_ty(&parameters.types[i]).into()
+                    } else if infer_types {
+                        // No type parameters were provided, we can infer all.
+                        if !default_needs_object_self(param) {
+                            self.ty_infer_for_def(param, span).into()
+                        } else {
+                            self.ty_infer(span).into()
+                        }
+                    } else if ty.has_default {
+                        // No type parameter provided, but a default exists.
+
+                        // If we are converting an object type, then the
+                        // `Self` parameter is unknown. However, some of the
+                        // other type parameters may reference `Self` in their
+                        // defaults. This will lead to an ICE if we are not
+                        // careful!
+                        if default_needs_object_self(param) {
+                            struct_span_err!(tcx.sess, span, E0393,
+                                             "the type parameter `{}` must be explicitly \
+                                             specified",
+                                             param.name)
+                                .span_label(span,
+                                            format!("missing reference to `{}`", param.name))
+                                .note(&format!("because of the default `Self` reference, \
+                                                type parameters must be specified on object \
+                                                types"))
+                                .emit();
+                            tcx.types.err.into()
+                        } else {
+                            // This is a default type parameter.
+                            self.normalize_ty(
+                                span,
+                                tcx.at(span).type_of(param.def_id)
+                                    .subst_spanned(tcx, substs, Some(span))
+                            ).into()
+                        }
+                    } else {
+                        // We've already errored above about the mismatch.
+                        tcx.types.err.into()
+                    }
                 }
-            } else {
-                // We've already errored above about the mismatch.
-                tcx.types.err
             }
         });
 
@@ -980,8 +1012,8 @@ pub fn def_to_ty(&self,
                 let item_id = tcx.hir.get_parent_node(node_id);
                 let item_def_id = tcx.hir.local_def_id(item_id);
                 let generics = tcx.generics_of(item_def_id);
-                let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)];
-                tcx.mk_param(index, tcx.hir.name(node_id).as_interned_str())
+                let index = generics.param_def_id_to_index[&tcx.hir.local_def_id(node_id)];
+                tcx.mk_ty_param(index, tcx.hir.name(node_id).as_interned_str())
             }
             Def::SelfTy(_, Some(def_id)) => {
                 // Self in impl (we know the concrete type).
@@ -1087,10 +1119,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
             hir::TyArray(ref ty, length) => {
                 let length_def_id = tcx.hir.body_owner_def_id(length);
                 let substs = Substs::identity_for_item(tcx, length_def_id);
-                let length = tcx.mk_const(ty::Const {
-                    val: ConstVal::Unevaluated(length_def_id, substs),
-                    ty: tcx.types.usize
-                });
+                let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
                 let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
@@ -1128,12 +1157,9 @@ pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) ->
         let mut substs = Vec::with_capacity(generics.count());
         if let Some(parent_id) = generics.parent {
             let parent_generics = tcx.generics_of(parent_id);
-            Substs::fill_item(
-                &mut substs, tcx, parent_generics,
-                &mut |def, _| tcx.mk_region(
-                    ty::ReEarlyBound(def.to_early_bound_region_data())),
-                &mut |def, _| tcx.mk_param_from_def(def)
-            );
+            Substs::fill_item(&mut substs, tcx, parent_generics, &mut |param, _| {
+                tcx.mk_param_from_def(param)
+            });
 
             // Replace all lifetimes with 'static
             for subst in &mut substs {
@@ -1143,10 +1169,10 @@ pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) ->
             }
             debug!("impl_trait_ty_to_ty: substs from parent = {:?}", substs);
         }
-        assert_eq!(substs.len(), generics.parent_count());
+        assert_eq!(substs.len(), generics.parent_count);
 
         // Fill in our own generics with the resolved lifetimes
-        assert_eq!(lifetimes.len(), generics.own_count());
+        assert_eq!(lifetimes.len(), generics.params.len());
         substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None))));
 
         debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
@@ -1303,10 +1329,12 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     (auto_traits, trait_bounds)
 }
 
-fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
-                             ty_param_defs: &[ty::TypeParameterDef]) {
-    let accepted = ty_param_defs.len();
-    let required = ty_param_defs.iter().take_while(|x| !x.has_default).count();
+fn check_type_argument_count(tcx: TyCtxt,
+                             span: Span,
+                             supplied: usize,
+                             ty_params: ParamRange)
+{
+    let (required, accepted) = (ty_params.required, ty_params.accepted);
     if supplied < required {
         let expected = if required < accepted {
             "expected at least"
index c7585c827ce11eaf92b0f0cbf59cd5ec1b0ec7a3..35cc70b08384ccabcc3c20679deafae51b73fa3d 100644 (file)
@@ -375,7 +375,7 @@ pub fn check_pat_walk(
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
-                        let size = size.val.unwrap_u64();
+                        let size = size.unwrap_usize(tcx);
                         let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
@@ -688,7 +688,7 @@ pub fn check_match(&self,
                     arm_span: arm.body.span,
                     source: match_src
                 });
-                coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get());
+                coercion.coerce(self, &cause, &arm.body, arm_ty);
             }
         }
 
index 94ef040d80a4f81e58180b0ef3861cdbb37f7353..c2ec6475b9c6596bb97cd9227c90f9f8ff89d254 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::infer::LateBoundRegionConversionTime;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::error_reporting::ArgKind;
-use rustc::ty::{self, ToPolyTraitRef, Ty};
+use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
 use rustc::ty::subst::Substs;
 use rustc::ty::TypeFoldable;
 use std::cmp;
@@ -104,15 +104,17 @@ fn check_closure(
         // inference phase (`upvar.rs`).
         let base_substs =
             Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
-        let substs = base_substs.extend_to(
-            self.tcx,
-            expr_def_id,
-            |_, _| span_bug!(expr.span, "closure has region param"),
-            |_, _| {
-                self.infcx
-                    .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
-            },
-        );
+        let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    span_bug!(expr.span, "closure has region param")
+                }
+                GenericParamDefKind::Type(_) => {
+                    self.infcx
+                        .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
+                }
+            }
+        });
         if let Some(GeneratorTypes { yield_ty, interior, movability }) = generator_types {
             let substs = ty::GeneratorSubsts { substs };
             self.demand_eqtype(
index c1ef916e27db3130204e7090ce92e89eacaca698..324af7b62704dfabd3c9802ea7b353855dd579b5 100644 (file)
@@ -60,7 +60,7 @@
 //! sort of a minor point so I've opted to leave it for later---after all
 //! we may want to adjust precisely when coercions occur.
 
-use check::{Diverges, FnCtxt, Needs};
+use check::{FnCtxt, Needs};
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -800,8 +800,7 @@ fn try_find_coercion_lub<E>(&self,
                                 exprs: &[E],
                                 prev_ty: Ty<'tcx>,
                                 new: &hir::Expr,
-                                new_ty: Ty<'tcx>,
-                                new_diverges: Diverges)
+                                new_ty: Ty<'tcx>)
                                 -> RelateResult<'tcx, Ty<'tcx>>
         where E: AsCoercionSite
     {
@@ -809,13 +808,6 @@ fn try_find_coercion_lub<E>(&self,
         let new_ty = self.resolve_type_vars_with_obligations(new_ty);
         debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
 
-        // Special-ish case: we can coerce any type `T` into the `!`
-        // type, but only if the source expression diverges.
-        if prev_ty.is_never() && new_diverges.always() {
-            debug!("permit coercion to `!` because expr diverges");
-            return Ok(prev_ty);
-        }
-
         // Special-case that coercion alone cannot handle:
         // Two function item types of differing IDs or Substs.
         if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) {
@@ -1054,14 +1046,12 @@ pub fn coerce<'a>(&mut self,
                       fcx: &FnCtxt<'a, 'gcx, 'tcx>,
                       cause: &ObligationCause<'tcx>,
                       expression: &'gcx hir::Expr,
-                      expression_ty: Ty<'tcx>,
-                      expression_diverges: Diverges)
+                      expression_ty: Ty<'tcx>)
     {
         self.coerce_inner(fcx,
                           cause,
                           Some(expression),
                           expression_ty,
-                          expression_diverges,
                           None, false)
     }
 
@@ -1087,7 +1077,6 @@ pub fn coerce_forced_unit<'a>(&mut self,
                           cause,
                           None,
                           fcx.tcx.mk_nil(),
-                          Diverges::Maybe,
                           Some(augment_error),
                           label_unit_as_expected)
     }
@@ -1100,7 +1089,6 @@ fn coerce_inner<'a>(&mut self,
                         cause: &ObligationCause<'tcx>,
                         expression: Option<&'gcx hir::Expr>,
                         mut expression_ty: Ty<'tcx>,
-                        expression_diverges: Diverges,
                         augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>,
                         label_expression_as_expected: bool)
     {
@@ -1134,15 +1122,13 @@ fn coerce_inner<'a>(&mut self,
                                                   exprs,
                                                   self.merged_ty(),
                                                   expression,
-                                                  expression_ty,
-                                                  expression_diverges),
+                                                  expression_ty),
                     Expressions::UpFront(ref coercion_sites) =>
                         fcx.try_find_coercion_lub(cause,
                                                   &coercion_sites[0..self.pushed],
                                                   self.merged_ty(),
                                                   expression,
-                                                  expression_ty,
-                                                  expression_diverges),
+                                                  expression_ty),
                 }
             }
         } else {
index 91264849cadf85f41f6930da4045cb23c54e89b1..ba950f90d0a02db5fa5bef9c87761ed0a139c673 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc::hir::{self, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, GenericParamDefKind};
 use rustc::ty::util::ExplicitSelf;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
@@ -357,8 +357,8 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 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[..];
+    let trait_params = trait_generics.own_counts().lifetimes;
+    let impl_params = impl_generics.own_counts().lifetimes;
 
     debug!("check_region_bounds_on_impl_method: \
             trait_generics={:?} \
@@ -377,7 +377,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // but found 0" it's confusing, because it looks like there
     // 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() {
+    if trait_params != impl_params {
         let mut err = struct_span_err!(tcx.sess,
                                        span,
                                        E0195,
@@ -574,8 +574,8 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         -> Result<(), ErrorReported> {
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    let num_impl_m_type_params = impl_m_generics.types.len();
-    let num_trait_m_type_params = trait_m_generics.types.len();
+    let num_impl_m_type_params = impl_m_generics.own_counts().types;
+    let num_trait_m_type_params = trait_m_generics.own_counts().types;
     if num_impl_m_type_params != num_trait_m_type_params {
         let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
         let impl_m_item = tcx.hir.expect_impl_item(impl_m_node_id);
@@ -728,11 +728,24 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut error_found = false;
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    for (impl_ty, trait_ty) in impl_m_generics.types.iter().zip(trait_m_generics.types.iter()) {
-        if impl_ty.synthetic != trait_ty.synthetic {
-            let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap();
+    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| {
+        match param.kind {
+            GenericParamDefKind::Type(ty) => Some((param.def_id, ty.synthetic)),
+            GenericParamDefKind::Lifetime => None,
+        }
+    });
+    let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
+        match param.kind {
+            GenericParamDefKind::Type(ty) => Some((param.def_id, ty.synthetic)),
+            GenericParamDefKind::Lifetime => None,
+        }
+    });
+    for ((impl_def_id, impl_synthetic),
+         (trait_def_id, trait_synthetic)) in impl_m_type_params.zip(trait_m_type_params) {
+        if impl_synthetic != trait_synthetic {
+            let impl_node_id = tcx.hir.as_local_node_id(impl_def_id).unwrap();
             let impl_span = tcx.hir.span(impl_node_id);
-            let trait_span = tcx.def_span(trait_ty.def_id);
+            let trait_span = tcx.def_span(trait_def_id);
             let mut err = struct_span_err!(tcx.sess,
                                            impl_span,
                                            E0643,
index fcf7541a159b02388449edd83fb53f0e0465d162..97e4a35ea4762a449220ad77c9fbd8521d53031b 100644 (file)
@@ -45,7 +45,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let i_n_tps = tcx.generics_of(def_id).types.len();
+    let i_n_tps = tcx.generics_of(def_id).own_counts().types;
     if i_n_tps != n_tps {
         let span = match it.node {
             hir::ForeignItemFn(_, _, ref generics) => generics.span,
@@ -76,7 +76,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// and in libcore/intrinsics.rs
 pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       it: &hir::ForeignItem) {
-    let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
+    let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
     let name = it.name.as_str();
     let (n_tps, inputs, output) = if name.starts_with("atomic_") {
         let split : Vec<&str> = name.split('_').collect();
@@ -342,11 +342,11 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                it: &hir::ForeignItem) {
     let param = |n| {
         let name = Symbol::intern(&format!("P{}", n)).as_interned_str();
-        tcx.mk_param(n, name)
+        tcx.mk_ty_param(n, name)
     };
 
     let def_id = tcx.hir.local_def_id(it.id);
-    let i_n_tps = tcx.generics_of(def_id).types.len();
+    let i_n_tps = tcx.generics_of(def_id).own_counts().types;
     let name = it.name.as_str();
 
     let (n_tps, inputs, output) = match &*name {
index 46288181037f49d596968d4bfa0b29736ec15b99..aa3a166d0656fd71136c0cafe013bb5a7a845da3 100644 (file)
@@ -15,7 +15,7 @@
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, GenericParamDefKind};
 use rustc::ty::subst::Subst;
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -314,30 +314,32 @@ fn instantiate_method_substs(&mut self,
 
         // Create subst for early-bound lifetime parameters, combining
         // parameters from the type and those from the method.
-        assert_eq!(method_generics.parent_count(), parent_substs.len());
+        assert_eq!(method_generics.parent_count, parent_substs.len());
         let provided = &segment.parameters;
-        Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
-            let i = def.index as usize;
+        let own_counts = method_generics.own_counts();
+        Substs::for_item(self.tcx, pick.item.def_id, |param, _| {
+            let i = param.index as usize;
             if i < parent_substs.len() {
-                parent_substs.region_at(i)
-            } else if let Some(lifetime)
-                    = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) {
-                AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
+                parent_substs[i]
             } else {
-                self.region_var_for_def(self.span, def)
-            }
-        }, |def, _cur_substs| {
-            let i = def.index as usize;
-            if i < parent_substs.len() {
-                parent_substs.type_at(i)
-            } else if let Some(ast_ty)
-                = provided.as_ref().and_then(|p| {
-                    p.types.get(i - parent_substs.len() - method_generics.regions.len())
-                })
-            {
-                self.to_ty(ast_ty)
-            } else {
-                self.type_var_for_def(self.span, def)
+                match param.kind {
+                    GenericParamDefKind::Lifetime => {
+                        if let Some(lifetime) = provided.as_ref().and_then(|p| {
+                            p.lifetimes.get(i - parent_substs.len())
+                        }) {
+                            return AstConv::ast_region_to_region(
+                                self.fcx, lifetime, Some(param)).into();
+                        }
+                    }
+                    GenericParamDefKind::Type(_) => {
+                        if let Some(ast_ty) = provided.as_ref().and_then(|p| {
+                            p.types.get(i - parent_substs.len() - own_counts.lifetimes)
+                        }) {
+                            return self.to_ty(ast_ty).into();
+                        }
+                    }
+                }
+                self.var_for_def(self.span, param)
             }
         })
     }
index 5f904a9419b1d6b85caf708d4460d5cd6682a428..15a8efd5885d77755c2ca725f822e64c5471b913 100644 (file)
@@ -19,6 +19,7 @@
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
 use rustc::ty::subst::Subst;
 use rustc::infer::{self, InferOk};
 
@@ -253,17 +254,18 @@ pub fn lookup_method_in_trait(&self,
                trait_def_id);
 
         // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let substs = Substs::for_item(self.tcx,
-                                      trait_def_id,
-                                      |def, _| self.region_var_for_def(span, def),
-                                      |def, _substs| {
-            if def.index == 0 {
-                self_ty
-            } else if let Some(ref input_types) = opt_input_types {
-                input_types[def.index as usize - 1]
-            } else {
-                self.type_var_for_def(span, def)
+        let substs = Substs::for_item(self.tcx, trait_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {}
+                GenericParamDefKind::Type(_) => {
+                    if param.index == 0 {
+                        return self_ty.into();
+                    } else if let Some(ref input_types) = opt_input_types {
+                        return input_types[param.index as usize - 1].into();
+                    }
+                }
             }
+            self.var_for_def(span, param)
         });
 
         let trait_ref = ty::TraitRef::new(trait_def_id, substs);
@@ -288,8 +290,7 @@ pub fn lookup_method_in_trait(&self,
         let method_item = self.associated_item(trait_def_id, m_name, Namespace::Value).unwrap();
         let def_id = method_item.def_id;
         let generics = tcx.generics_of(def_id);
-        assert_eq!(generics.types.len(), 0);
-        assert_eq!(generics.regions.len(), 0);
+        assert_eq!(generics.params.len(), 0);
 
         debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
         let mut obligations = vec![];
index e45565c2f52203783f1389b2a79d11f21d6f1869..6b860dbe8febbfee9a756afe14eb848d3f613fb0 100644 (file)
@@ -20,6 +20,7 @@
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
 use rustc::infer::{self, InferOk};
@@ -1378,31 +1379,28 @@ fn xform_method_sig(&self,
         // method yet. So create fresh variables here for those too,
         // if there are any.
         let generics = self.tcx.generics_of(method);
-        assert_eq!(substs.types().count(), generics.parent_types as usize);
-        assert_eq!(substs.regions().count(), generics.parent_regions as usize);
+        assert_eq!(substs.len(), generics.parent_count as usize);
 
         // Erase any late-bound regions from the method and substitute
         // in the values from the substitution.
         let xform_fn_sig = self.erase_late_bound_regions(&fn_sig);
 
-        if generics.types.is_empty() && generics.regions.is_empty() {
+        if generics.params.is_empty() {
             xform_fn_sig.subst(self.tcx, substs)
         } else {
-            let substs = Substs::for_item(self.tcx, method, |def, _| {
-                let i = def.index as usize;
+            let substs = Substs::for_item(self.tcx, method, |param, _| {
+                let i = param.index as usize;
                 if i < substs.len() {
-                    substs.region_at(i)
+                    substs[i]
                 } else {
-                    // In general, during probe we erase regions. See
-                    // `impl_self_ty()` for an explanation.
-                    self.tcx.types.re_erased
-                }
-            }, |def, _cur_substs| {
-                let i = def.index as usize;
-                if i < substs.len() {
-                    substs.type_at(i)
-                } else {
-                    self.type_var_for_def(self.span, def)
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            // In general, during probe we erase regions. See
+                            // `impl_self_ty()` for an explanation.
+                            self.tcx.types.re_erased.into()
+                        }
+                        GenericParamDefKind::Type(_) => self.var_for_def(self.span, param),
+                    }
                 }
             });
             xform_fn_sig.subst(self.tcx, substs)
@@ -1415,12 +1413,15 @@ fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx
     }
 
     fn fresh_item_substs(&self, def_id: DefId) -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx,
-                         def_id,
-                         |_, _| self.tcx.types.re_erased,
-                         |_, _| self.next_ty_var(
-                             TypeVariableOrigin::SubstitutionPlaceholder(
-                                 self.tcx.def_span(def_id))))
+        Substs::for_item(self.tcx, def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(),
+                GenericParamDefKind::Type(_) => {
+                    self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder(
+                        self.tcx.def_span(def_id))).into()
+                }
+            }
+        })
     }
 
     /// Replace late-bound-regions bound by `value` with `'static` using
index ef14fa9a12248eb5a49d189eda474601d617e778..f98a8ba1e4d6c70fc52291109def800ac667206b 100644 (file)
@@ -94,9 +94,9 @@
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{GlobalId};
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
-use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::maps::Providers;
@@ -542,7 +542,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// you get indicates whether any subexpression that was
     /// evaluating up to and including `X` diverged.
     ///
-    /// We use this flag for two purposes:
+    /// We currently use this flag only for diagnostic purposes:
     ///
     /// - To warn about unreachable code: if, after processing a
     ///   sub-expression but before we have applied the effects of the
@@ -556,16 +556,8 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ///   foo();}` or `{return; 22}`, where we would warn on the
     ///   `foo()` or `22`.
     ///
-    /// - To permit assignment into a local variable or other place
-    ///   (including the "return slot") of type `!`.  This is allowed
-    ///   if **either** the type of value being assigned is `!`, which
-    ///   means the current code is dead, **or** the expression's
-    ///   diverging flag is true, which means that a diverging value was
-    ///   wrapped (e.g., `let x: ! = foo(return)`).
-    ///
-    /// To repeat the last point: an expression represents dead-code
-    /// if, after checking it, **either** its type is `!` OR the
-    /// diverges flag is set to something other than `Maybe`.
+    /// An expression represents dead-code if, after checking it,
+    /// the diverges flag is set to something other than `Maybe`.
     diverges: Cell<Diverges>,
 
     /// Whether any child nodes have any type errors.
@@ -1247,7 +1239,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
         } else {
             for item in &m.items {
                 let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
-                if !generics.types.is_empty() {
+                if generics.params.len() - generics.own_counts().lifetimes != 0 {
                     let mut err = struct_span_err!(tcx.sess, item.span, E0044,
                         "foreign items may not have type parameters");
                     err.span_label(item.span, "can't have type parameters");
@@ -1724,7 +1716,7 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
         let item_id = tcx.hir.ty_param_owner(node_id);
         let item_def_id = tcx.hir.local_def_id(item_id);
         let generics = tcx.generics_of(item_def_id);
-        let index = generics.type_param_to_index[&def_id];
+        let index = generics.param_def_id_to_index[&def_id];
         ty::GenericPredicates {
             parent: None,
             predicates: self.param_env.caller_bounds.iter().filter(|predicate| {
@@ -1738,7 +1730,7 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
         }
     }
 
-    fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
+    fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
                 -> Option<ty::Region<'tcx>> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name),
@@ -1752,9 +1744,12 @@ fn ty_infer(&self, span: Span) -> Ty<'tcx> {
     }
 
     fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::TypeParameterDef,
+                        ty_param_def: &ty::GenericParamDef,
                         span: Span) -> Ty<'tcx> {
-        self.type_var_for_def(span, ty_param_def)
+        if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
+            return ty;
+        }
+        unreachable!()
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -3002,8 +2997,7 @@ fn check_return_expr(&self, return_expr: &'gcx hir::Expr) {
                             &self.cause(return_expr.span,
                                         ObligationCauseCode::ReturnType(return_expr.id)),
                             return_expr,
-                            return_expr_ty,
-                            self.diverges.get());
+                            return_expr_ty);
     }
 
 
@@ -3034,13 +3028,13 @@ fn check_then_else(&self,
         let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty);
 
         let if_cause = self.cause(sp, ObligationCauseCode::IfExpression);
-        coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges);
+        coerce.coerce(self, &if_cause, then_expr, then_ty);
 
         if let Some(else_expr) = opt_else_expr {
             let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let else_diverges = self.diverges.get();
 
-            coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges);
+            coerce.coerce(self, &if_cause, else_expr, else_ty);
 
             // We won't diverge unless both branches do (or the condition does).
             self.diverges.set(cond_diverges | then_diverges & else_diverges);
@@ -3067,7 +3061,7 @@ fn check_field(&self,
                    base: &'gcx hir::Expr,
                    field: &Spanned<ast::Name>) -> Ty<'tcx> {
         let expr_t = self.check_expr_with_needs(base, needs);
-        let expr_t = self.structurally_resolved_type(expr.span,
+        let expr_t = self.structurally_resolved_type(base.span,
                                                      expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -3081,12 +3075,14 @@ fn check_field(&self,
                     if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) {
                         let field = &fields[index];
                         let field_ty = self.field_ty(expr.span, field, substs);
+                        // Save the index of all fields regardless of their visibility in case
+                        // of error recovery.
+                        self.write_field_index(expr.id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
                             let adjustments = autoderef.adjust_steps(needs);
                             self.apply_adjustments(base, adjustments);
                             autoderef.finalize();
 
-                            self.write_field_index(expr.id, index);
                             self.tcx.check_stability(field.did, Some(expr.id), expr.span);
                             return field_ty;
                         }
@@ -3278,7 +3274,7 @@ fn check_expr_struct_fields(&self,
                                 span: Span,
                                 variant: &'tcx ty::VariantDef,
                                 ast_fields: &'gcx [hir::Field],
-                                check_completeness: bool) {
+                                check_completeness: bool) -> bool {
         let tcx = self.tcx;
 
         let adt_ty_hint =
@@ -3380,6 +3376,7 @@ fn check_expr_struct_fields(&self,
                                           truncated_fields_error))
                 .emit();
         }
+        error_happened
     }
 
     fn check_struct_fields_on_error(&self,
@@ -3478,24 +3475,29 @@ fn check_expr_struct(&self,
             }
         }
 
-        self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields,
-                                      base_expr.is_none());
+        let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span,
+                                                           variant, fields, base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type_or_error(base_expr, struct_ty);
-            match struct_ty.sty {
-                ty::TyAdt(adt, substs) if adt.is_struct() => {
-                    let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
-                        self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
-                    }).collect();
-
-                    self.tables
-                        .borrow_mut()
-                        .fru_field_types_mut()
-                        .insert(expr.hir_id, fru_field_types);
-                }
-                _ => {
-                    span_err!(self.tcx.sess, base_expr.span, E0436,
-                              "functional record update syntax requires a struct");
+            // If check_expr_struct_fields hit an error, do not attempt to populate
+            // the fields with the base_expr. This could cause us to hit errors later
+            // when certain fields are assumed to exist that in fact do not.
+            if !error_happened {
+                self.check_expr_has_type_or_error(base_expr, struct_ty);
+                match struct_ty.sty {
+                    ty::TyAdt(adt, substs) if adt.is_struct() => {
+                        let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
+                            self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
+                        }).collect();
+
+                        self.tables
+                            .borrow_mut()
+                            .fru_field_types_mut()
+                            .insert(expr.hir_id, fru_field_types);
+                    }
+                    _ => {
+                        span_err!(self.tcx.sess, base_expr.span, E0436,
+                                  "functional record update syntax requires a struct");
+                    }
                 }
             }
         }
@@ -3724,8 +3726,8 @@ fn check_expr_kind(&self,
               tcx.mk_nil()
           }
           hir::ExprBreak(destination, ref expr_opt) => {
-              if let Some(target_id) = destination.target_id.opt_id() {
-                  let (e_ty, e_diverges, cause);
+              if let Ok(target_id) = destination.target_id {
+                  let (e_ty, cause);
                   if let Some(ref e) = *expr_opt {
                       // If this is a break with a value, we need to type-check
                       // the expression. Get an expected type from the loop context.
@@ -3744,13 +3746,11 @@ fn check_expr_kind(&self,
 
                       // Recurse without `enclosing_breakables` borrowed.
                       e_ty = self.check_expr_with_hint(e, coerce_to);
-                      e_diverges = self.diverges.get();
                       cause = self.misc(e.span);
                   } else {
                       // Otherwise, this is a break *without* a value. That's
                       // always legal, and is equivalent to `break ()`.
                       e_ty = tcx.mk_nil();
-                      e_diverges = Diverges::Maybe;
                       cause = self.misc(expr.span);
                   }
 
@@ -3761,7 +3761,7 @@ fn check_expr_kind(&self,
                   let ctxt = enclosing_breakables.find_breakable(target_id);
                   if let Some(ref mut coerce) = ctxt.coerce {
                       if let Some(ref e) = *expr_opt {
-                          coerce.coerce(self, &cause, e, e_ty, e_diverges);
+                          coerce.coerce(self, &cause, e, e_ty);
                       } else {
                           assert!(e_ty.is_nil());
                           coerce.coerce_forced_unit(self, &cause, &mut |_| (), true);
@@ -3967,7 +3967,7 @@ fn check_expr_kind(&self,
                   for e in args {
                       let e_ty = self.check_expr_with_hint(e, coerce_to);
                       let cause = self.misc(e.span);
-                      coerce.coerce(self, &cause, e, e_ty, self.diverges.get());
+                      coerce.coerce(self, &cause, e, e_ty);
                   }
                   coerce.complete(self)
               } else {
@@ -4018,7 +4018,7 @@ fn check_expr_kind(&self,
             };
 
             if let Ok(count) = count {
-                let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
+                let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
                 if !zero_or_one {
                     // For [foo, ..n] where n > 1, `foo` must have
                     // Copy type:
@@ -4080,7 +4080,7 @@ fn check_expr_kind(&self,
               } else if idx_t.references_error() {
                   idx_t
               } else {
-                  let base_t = self.structurally_resolved_type(expr.span, base_t);
+                  let base_t = self.structurally_resolved_type(base.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
                       Some((index_ty, element_ty)) => {
                           // two-phase not needed because index_ty is never mutable
@@ -4378,8 +4378,7 @@ fn check_block_with_expected(&self,
                 coerce.coerce(self,
                               &cause,
                               tail_expr,
-                              tail_expr_ty,
-                              self.diverges.get());
+                              tail_expr_ty);
             } else {
                 // Subtle: if there is no explicit tail expression,
                 // that is typically equivalent to a tail expression
@@ -4755,73 +4754,77 @@ pub fn instantiate_value_path(&self,
 
         let (fn_start, has_self) = match (type_segment, fn_segment) {
             (_, Some((_, generics))) => {
-                (generics.parent_count(), generics.has_self)
+                (generics.parent_count, generics.has_self)
             }
             (Some((_, generics)), None) => {
-                (generics.own_count(), generics.has_self)
+                (generics.params.len(), generics.has_self)
             }
             (None, None) => (0, false)
         };
-        let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
-            let mut i = def.index as usize;
+        let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
+            let mut i = param.index as usize;
 
             let segment = if i < fn_start {
+                if let GenericParamDefKind::Type(_) = param.kind {
+                    // Handle Self first, so we can adjust the index to match the AST.
+                    if has_self && i == 0 {
+                        return opt_self_ty.map(|ty| Kind::from(ty)).unwrap_or_else(|| {
+                            self.var_for_def(span, param)
+                        });
+                    }
+                }
                 i -= has_self as usize;
                 type_segment
             } else {
                 i -= fn_start;
                 fn_segment
             };
-            let lifetimes = segment.map_or(&[][..], |(s, _)| {
-                s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
-            });
-
-            if let Some(lifetime) = lifetimes.get(i) {
-                AstConv::ast_region_to_region(self, lifetime, Some(def))
-            } else {
-                self.re_infer(span, Some(def)).unwrap()
-            }
-        }, |def, substs| {
-            let mut i = def.index as usize;
 
-            let segment = if i < fn_start {
-                // Handle Self first, so we can adjust the index to match the AST.
-                if has_self && i == 0 {
-                    return opt_self_ty.unwrap_or_else(|| {
-                        self.type_var_for_def(span, def)
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    let lifetimes = segment.map_or(&[][..], |(s, _)| {
+                        s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
                     });
+
+                    if let Some(lifetime) = lifetimes.get(i) {
+                        AstConv::ast_region_to_region(self, lifetime, Some(param)).into()
+                    } else {
+                        self.re_infer(span, Some(param)).unwrap().into()
+                    }
                 }
-                i -= has_self as usize;
-                type_segment
-            } else {
-                i -= fn_start;
-                fn_segment
-            };
-            let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
-                (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
-            });
+                GenericParamDefKind::Type(_) => {
+                    let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
+                        (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
+                    });
 
-            // Skip over the lifetimes in the same segment.
-            if let Some((_, generics)) = segment {
-                i -= generics.regions.len();
-            }
+                    // Skip over the lifetimes in the same segment.
+                    if let Some((_, generics)) = segment {
+                        i -= generics.own_counts().lifetimes;
+                    }
 
-            if let Some(ast_ty) = types.get(i) {
-                // A provided type parameter.
-                self.to_ty(ast_ty)
-            } else if !infer_types && def.has_default {
-                // No type parameter provided, but a default exists.
-                let default = self.tcx.type_of(def.def_id);
-                self.normalize_ty(
-                    span,
-                    default.subst_spanned(self.tcx, substs, Some(span))
-                )
-            } else {
-                // No type parameters were provided, we can infer all.
-                // This can also be reached in some error cases:
-                // We prefer to use inference variables instead of
-                // TyError to let type inference recover somewhat.
-                self.type_var_for_def(span, def)
+                    let has_default = match param.kind {
+                        GenericParamDefKind::Type(ty) => ty.has_default,
+                        _ => unreachable!()
+                    };
+
+                    if let Some(ast_ty) = types.get(i) {
+                        // A provided type parameter.
+                        self.to_ty(ast_ty).into()
+                    } else if !infer_types && has_default {
+                        // No type parameter provided, but a default exists.
+                        let default = self.tcx.type_of(param.def_id);
+                        self.normalize_ty(
+                            span,
+                            default.subst_spanned(self.tcx, substs, Some(span))
+                        ).into()
+                    } else {
+                        // No type parameters were provided, we can infer all.
+                        // This can also be reached in some error cases:
+                        // We prefer to use inference variables instead of
+                        // TyError to let type inference recover somewhat.
+                        self.var_for_def(span, param)
+                    }
+                }
             }
         });
 
@@ -4921,18 +4924,40 @@ fn check_path_parameter_count(&self,
             format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
         };
 
-        // Check provided type parameters.
-        let type_defs = segment.map_or(&[][..], |(_, generics)| {
-            if generics.parent.is_none() {
-                &generics.types[generics.has_self as usize..]
-            } else {
-                &generics.types
-            }
-        });
-        let required_len = type_defs.iter().take_while(|d| !d.has_default).count();
-        if types.len() > type_defs.len() {
-            let span = types[type_defs.len()].span;
-            let expected_text = count_type_params(type_defs.len());
+        // Check provided parameters.
+        let ((ty_required, ty_accepted), lt_accepted) =
+            segment.map_or(((0, 0), 0), |(_, generics)| {
+                struct ParamRange {
+                    required: usize,
+                    accepted: usize
+                };
+
+                let mut lt_accepted = 0;
+                let mut ty_params = ParamRange { required: 0, accepted: 0 };
+                for param in &generics.params {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            lt_accepted += 1;
+                        }
+                        GenericParamDefKind::Type(ty) => {
+                            ty_params.accepted += 1;
+                            if !ty.has_default {
+                                ty_params.required += 1;
+                            }
+                        }
+                    };
+                }
+                if generics.parent.is_none() && generics.has_self {
+                    ty_params.required -= 1;
+                    ty_params.accepted -= 1;
+                }
+
+                ((ty_params.required, ty_params.accepted), lt_accepted)
+            });
+
+        if types.len() > ty_accepted {
+            let span = types[ty_accepted].span;
+            let expected_text = count_type_params(ty_accepted);
             let actual_text = count_type_params(types.len());
             struct_span_err!(self.tcx.sess, span, E0087,
                              "too many type parameters provided: \
@@ -4945,8 +4970,8 @@ fn check_path_parameter_count(&self,
             // type parameters, we force instantiate_value_path to
             // use inference variables instead of the provided types.
             *segment = None;
-        } else if types.len() < required_len && !infer_types && !supress_mismatch_error {
-            let expected_text = count_type_params(required_len);
+        } else if types.len() < ty_required && !infer_types && !supress_mismatch_error {
+            let expected_text = count_type_params(ty_required);
             let actual_text = count_type_params(types.len());
             struct_span_err!(self.tcx.sess, span, E0089,
                              "too few type parameters provided: \
@@ -4960,10 +4985,6 @@ fn check_path_parameter_count(&self,
             AstConv::prohibit_projection(self, bindings[0].span);
         }
 
-        // Check provided lifetime parameters.
-        let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
-        let required_len = lifetime_defs.len();
-
         // Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
         let has_late_bound_lifetime_defs =
             segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
@@ -4972,8 +4993,8 @@ fn check_path_parameter_count(&self,
             let primary_msg = "cannot specify lifetime arguments explicitly \
                                if late bound lifetime parameters are present";
             let note_msg = "the late bound lifetime parameter is introduced here";
-            if !is_method_call && (lifetimes.len() > lifetime_defs.len() ||
-                                   lifetimes.len() < required_len && !infer_lifetimes) {
+            if !is_method_call && (lifetimes.len() > lt_accepted ||
+                                   lifetimes.len() < lt_accepted && !infer_lifetimes) {
                 let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
                 err.span_note(span_late, note_msg);
                 err.emit();
@@ -4987,9 +5008,9 @@ fn check_path_parameter_count(&self,
             return;
         }
 
-        if lifetimes.len() > lifetime_defs.len() {
-            let span = lifetimes[lifetime_defs.len()].span;
-            let expected_text = count_lifetime_params(lifetime_defs.len());
+        if lifetimes.len() > lt_accepted {
+            let span = lifetimes[lt_accepted].span;
+            let expected_text = count_lifetime_params(lt_accepted);
             let actual_text = count_lifetime_params(lifetimes.len());
             struct_span_err!(self.tcx.sess, span, E0088,
                              "too many lifetime parameters provided: \
@@ -4997,8 +5018,8 @@ fn check_path_parameter_count(&self,
                              expected_text, actual_text)
                 .span_label(span, format!("expected {}", expected_text))
                 .emit();
-        } else if lifetimes.len() < required_len && !infer_lifetimes {
-            let expected_text = count_lifetime_params(lifetime_defs.len());
+        } else if lifetimes.len() < lt_accepted && !infer_lifetimes {
+            let expected_text = count_lifetime_params(lt_accepted);
             let actual_text = count_lifetime_params(lifetimes.len());
             struct_span_err!(self.tcx.sess, span, E0090,
                              "too few lifetime parameters provided: \
@@ -5014,17 +5035,16 @@ fn check_impl_trait(&self,
                         span: Span,
                         segment: &mut Option<(&hir::PathSegment, &ty::Generics)>)
                         -> bool {
-        use hir::SyntheticTyParamKind::*;
-
         let segment = segment.map(|(path_segment, generics)| {
             let explicit = !path_segment.infer_types;
-            let impl_trait = generics.types.iter()
-                                           .any(|ty_param| {
-                                               match ty_param.synthetic {
-                                                   Some(ImplTrait) => true,
-                                                   _ => false,
-                                               }
-                                           });
+            let impl_trait = generics.params.iter().any(|param| {
+                if let ty::GenericParamDefKind::Type(ty) = param.kind {
+                    if let Some(hir::SyntheticTyParamKind::ImplTrait) = ty.synthetic {
+                        return true;
+                    }
+                }
+                false
+            });
 
             if explicit && impl_trait {
                 let mut err = struct_span_err! {
@@ -5053,7 +5073,9 @@ pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.need_type_info((**self).body_id, sp, ty);
+                self.need_type_info_err((**self).body_id, sp, ty)
+                    .note("type must be known at this point")
+                    .emit();
             }
             self.demand_suptype(sp, self.tcx.types.err, ty);
             self.tcx.types.err
index 9e8e00594e60afc9074322c7b080ac6c09294f7f..23081b87d2651e4f7ec1bfc1143d9b7d90f0aa7c 100644 (file)
@@ -12,8 +12,8 @@
 
 use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
 use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
@@ -246,76 +246,151 @@ fn check_overloaded_binop(&self,
             Err(()) => {
                 // error types are considered "builtin"
                 if !lhs_ty.references_error() {
-                    if let IsAssign::Yes = is_assign {
-                        struct_span_err!(self.tcx.sess, expr.span, E0368,
-                                         "binary assignment operation `{}=` \
-                                          cannot be applied to type `{}`",
-                                         op.node.as_str(),
-                                         lhs_ty)
-                            .span_label(lhs_expr.span,
-                                        format!("cannot use `{}=` on type `{}`",
-                                        op.node.as_str(), lhs_ty))
-                            .emit();
-                    } else {
-                        let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
-                            "binary operation `{}` cannot be applied to type `{}`",
-                            op.node.as_str(),
-                            lhs_ty);
-
-                        if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
-                            if {
-                                !self.infcx.type_moves_by_default(self.param_env,
-                                                                  rty,
-                                                                  lhs_expr.span) &&
-                                    self.lookup_op_method(rty,
-                                                          &[rhs_ty],
-                                                          Op::Binary(op, is_assign))
-                                        .is_ok()
-                            } {
-                                err.note(
-                                    &format!(
-                                        "this is a reference to a type that `{}` can be applied \
-                                        to; you need to dereference this variable once for this \
-                                        operation to work",
-                                    op.node.as_str()));
+                    let codemap = self.tcx.sess.codemap();
+                    match is_assign {
+                        IsAssign::Yes => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
+                                                "binary assignment operation `{}=` \
+                                                cannot be applied to type `{}`",
+                                                op.node.as_str(),
+                                                lhs_ty);
+                            err.span_label(lhs_expr.span,
+                                    format!("cannot use `{}=` on type `{}`",
+                                    op.node.as_str(), lhs_ty));
+                            let mut suggested_deref = false;
+                            if let TyRef(_, mut rty, _) = lhs_ty.sty {
+                                if {
+                                    !self.infcx.type_moves_by_default(self.param_env,
+                                                                        rty,
+                                                                        lhs_expr.span) &&
+                                        self.lookup_op_method(rty,
+                                                              &[rhs_ty],
+                                                              Op::Binary(op, is_assign))
+                                            .is_ok()
+                                } {
+                                    if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+                                        while let TyRef(_, rty_inner, _) = rty.sty {
+                                            rty = rty_inner;
+                                        }
+                                        let msg = &format!(
+                                                "`{}=` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(),
+                                                rty,
+                                                lstring
+                                        );
+                                        err.help(msg);
+                                        suggested_deref = true;
+                                    }
+                                }
                             }
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::AddAssign"),
+                                hir::BiSub    => Some("std::ops::SubAssign"),
+                                hir::BiMul    => Some("std::ops::MulAssign"),
+                                hir::BiDiv    => Some("std::ops::DivAssign"),
+                                hir::BiRem    => Some("std::ops::RemAssign"),
+                                hir::BiBitAnd => Some("std::ops::BitAndAssign"),
+                                hir::BiBitXor => Some("std::ops::BitXorAssign"),
+                                hir::BiBitOr  => Some("std::ops::BitOrAssign"),
+                                hir::BiShl    => Some("std::ops::ShlAssign"),
+                                hir::BiShr    => Some("std::ops::ShrAssign"),
+                                _             => None
+                            };
+                            if let Some(missing_trait) = missing_trait {
+                                if op.node == hir::BiAdd &&
+                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+                                                            rhs_ty, &mut err) {
+                                    // This has nothing here because it means we did string
+                                    // concatenation (e.g. "Hello " + "World!"). This means
+                                    // we don't want the note in the else clause to be emitted
+                                } else if let ty::TyParam(_) = lhs_ty.sty {
+                                    // FIXME: point to span of param
+                                    err.note(&format!(
+                                        "`{}` might need a bound for `{}`",
+                                        lhs_ty, missing_trait
+                                    ));
+                                } else if !suggested_deref {
+                                    err.note(&format!(
+                                        "an implementation of `{}` might \
+                                         be missing for `{}`",
+                                        missing_trait, lhs_ty
+                                    ));
+                                }
+                            }
+                            err.emit();
                         }
-
-                        let missing_trait = match op.node {
-                            hir::BiAdd    => Some("std::ops::Add"),
-                            hir::BiSub    => Some("std::ops::Sub"),
-                            hir::BiMul    => Some("std::ops::Mul"),
-                            hir::BiDiv    => Some("std::ops::Div"),
-                            hir::BiRem    => Some("std::ops::Rem"),
-                            hir::BiBitAnd => Some("std::ops::BitAnd"),
-                            hir::BiBitOr  => Some("std::ops::BitOr"),
-                            hir::BiShl    => Some("std::ops::Shl"),
-                            hir::BiShr    => Some("std::ops::Shr"),
-                            hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
-                            hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
-                                Some("std::cmp::PartialOrd"),
-                            _             => None
-                        };
-
-                        if let Some(missing_trait) = missing_trait {
-                            if missing_trait == "std::ops::Add" &&
-                                self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                        rhs_ty, &mut err) {
-                                // This has nothing here because it means we did string
-                                // concatenation (e.g. "Hello " + "World!"). This means
-                                // we don't want the note in the else clause to be emitted
-                            } else if let ty::TyParam(_) = lhs_ty.sty {
-                                // FIXME: point to span of param
-                                err.note(
-                                    &format!("`{}` might need a bound for `{}`",
-                                             lhs_ty, missing_trait));
-                            } else {
-                                err.note(
-                                    &format!("an implementation of `{}` might be missing for `{}`",
-                                             missing_trait, lhs_ty));
+                        IsAssign::No => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
+                                            "binary operation `{}` cannot be applied to type `{}`",
+                                            op.node.as_str(),
+                                            lhs_ty);
+                            let mut suggested_deref = false;
+                            if let TyRef(_, mut rty, _) = lhs_ty.sty {
+                                if {
+                                    !self.infcx.type_moves_by_default(self.param_env,
+                                                                        rty,
+                                                                        lhs_expr.span) &&
+                                        self.lookup_op_method(rty,
+                                                              &[rhs_ty],
+                                                              Op::Binary(op, is_assign))
+                                            .is_ok()
+                                } {
+                                    if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+                                        while let TyRef(_, rty_inner, _) = rty.sty {
+                                            rty = rty_inner;
+                                        }
+                                        let msg = &format!(
+                                                "`{}` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(),
+                                                rty,
+                                                lstring
+                                        );
+                                        err.help(msg);
+                                        suggested_deref = true;
+                                    }
+                                }
                             }
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::Add"),
+                                hir::BiSub    => Some("std::ops::Sub"),
+                                hir::BiMul    => Some("std::ops::Mul"),
+                                hir::BiDiv    => Some("std::ops::Div"),
+                                hir::BiRem    => Some("std::ops::Rem"),
+                                hir::BiBitAnd => Some("std::ops::BitAnd"),
+                                hir::BiBitXor => Some("std::ops::BitXor"),
+                                hir::BiBitOr  => Some("std::ops::BitOr"),
+                                hir::BiShl    => Some("std::ops::Shl"),
+                                hir::BiShr    => Some("std::ops::Shr"),
+                                hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+                                hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+                                    Some("std::cmp::PartialOrd"),
+                                _             => None
+                            };
+                            if let Some(missing_trait) = missing_trait {
+                                if op.node == hir::BiAdd &&
+                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+                                                            rhs_ty, &mut err) {
+                                    // This has nothing here because it means we did string
+                                    // concatenation (e.g. "Hello " + "World!"). This means
+                                    // we don't want the note in the else clause to be emitted
+                                } else if let ty::TyParam(_) = lhs_ty.sty {
+                                    // FIXME: point to span of param
+                                    err.note(&format!(
+                                        "`{}` might need a bound for `{}`",
+                                        lhs_ty, missing_trait
+                                    ));
+                                } else if !suggested_deref {
+                                    err.note(&format!(
+                                        "an implementation of `{}` might \
+                                         be missing for `{}`",
+                                        missing_trait, lhs_ty
+                                    ));
+                                }
+                            }
+                            err.emit();
                         }
-                        err.emit();
                     }
                 }
                 self.tcx.types.err
@@ -393,9 +468,29 @@ pub fn check_user_unop(&self,
             Err(()) => {
                 let actual = self.resolve_type_vars_if_possible(&operand_ty);
                 if !actual.references_error() {
-                    struct_span_err!(self.tcx.sess, ex.span, E0600,
+                    let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
                                      "cannot apply unary operator `{}` to type `{}`",
-                                     op.as_str(), actual).emit();
+                                     op.as_str(), actual);
+                    err.span_label(ex.span, format!("cannot apply unary \
+                                                    operator `{}`", op.as_str()));
+                    match actual.sty {
+                        TyUint(_) if op == hir::UnNeg => {
+                            err.note(&format!("unsigned values cannot be negated"));
+                        },
+                        TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
+                        TyRef(_, ref lty, _) if lty.sty == TyStr => {},
+                        _ => {
+                            let missing_trait = match op {
+                                hir::UnNeg => "std::ops::Neg",
+                                hir::UnNot => "std::ops::Not",
+                                hir::UnDeref => "std::ops::UnDerf"
+                            };
+                            err.note(&format!("an implementation of `{}` might \
+                                                be missing for `{}`",
+                                             missing_trait, operand_ty));
+                        }
+                    }
+                    err.emit();
                 }
                 self.tcx.types.err
             }
index d0ff44c8e7e10e65da9a3ad874edecb4ecdf7cb3..0fc8c9cc316aca0188d71b184fcf147e88b7faff 100644 (file)
@@ -13,7 +13,8 @@
 
 use hir::def_id::DefId;
 use rustc::traits::{self, ObligationCauseCode};
-use rustc::ty::{self, Lift, Ty, TyCtxt};
+use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::subst::Substs;
 use rustc::ty::util::ExplicitSelf;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::middle::lang_items;
@@ -46,6 +47,12 @@ fn with_fcx<F>(&'tcx mut self, f: F) where
         let param_env = self.param_env;
         self.inherited.enter(|inh| {
             let fcx = FnCtxt::new(&inh, param_env, id);
+            if !inh.tcx.features().trivial_bounds {
+                // As predicates are cached rather than obligations, this
+                // needsto be called first so that they are checked with an
+                // empty param_env.
+                check_false_global_bounds(&fcx, span, id);
+            }
             let wf_tys = f(&fcx, fcx.tcx.global_tcx());
             fcx.select_all_obligations_or_error();
             fcx.regionck_item(id, span, &wf_tys);
@@ -187,7 +194,7 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 fcx.register_wf_obligation(ty, span, code.clone());
             }
             ty::AssociatedKind::Method => {
-                reject_shadowing_type_parameters(fcx.tcx, item.def_id);
+                reject_shadowing_parameters(fcx.tcx, item.def_id);
                 let sig = fcx.tcx.fn_sig(item.def_id);
                 let sig = fcx.normalize_associated_types_in(span, &sig);
                 check_fn_or_method(tcx, fcx, span, sig,
@@ -368,21 +375,31 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     let mut substituted_predicates = Vec::new();
 
     let generics = tcx.generics_of(def_id);
-    let is_our_default = |def: &ty::TypeParameterDef|
-                            def.has_default && def.index >= generics.parent_count() as u32;
+    let is_our_default = |def: &ty::GenericParamDef| {
+        match def.kind {
+            GenericParamDefKind::Type(ty) => {
+                ty.has_default && def.index >= generics.parent_count as u32
+            }
+            _ => unreachable!()
+        }
+    };
 
     // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
     // For example this forbids the declaration:
     // struct Foo<T = Vec<[u32]>> { .. }
     // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
-    for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
-        let ty = fcx.tcx.type_of(d);
-        // ignore dependent defaults -- that is, where the default of one type
-        // parameter includes another (e.g., <T, U = T>). In those cases, we can't
-        // be sure if it will error or not as user might always specify the other.
-        if !ty.needs_subst() {
-            fcx.register_wf_obligation(ty, fcx.tcx.def_span(d),
-                ObligationCauseCode::MiscObligation);
+    for param in &generics.params {
+        if let GenericParamDefKind::Type(_) = param.kind {
+            if is_our_default(&param) {
+                let ty = fcx.tcx.type_of(param.def_id);
+                // ignore dependent defaults -- that is, where the default of one type
+                // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+                // be sure if it will error or not as user might always specify the other.
+                if !ty.needs_subst() {
+                    fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id),
+                        ObligationCauseCode::MiscObligation);
+                }
+            }
         }
     }
 
@@ -394,22 +411,27 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
     //
     // First we build the defaulted substitution.
-    let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
-            // All regions are identity.
-            fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-        }, |def, _| {
-            // If the param has a default,
-            if is_our_default(def) {
-                let default_ty = fcx.tcx.type_of(def.def_id);
-                // and it's not a dependent default
-                if !default_ty.needs_subst() {
-                    // then substitute with the default.
-                    return default_ty;
+    let substs = Substs::for_item(fcx.tcx, def_id, |param, _| {
+        match param.kind {
+            GenericParamDefKind::Lifetime => {
+                // All regions are identity.
+                fcx.tcx.mk_param_from_def(param)
+            }
+            GenericParamDefKind::Type(_) => {
+                // If the param has a default,
+                if is_our_default(param) {
+                    let default_ty = fcx.tcx.type_of(param.def_id);
+                    // and it's not a dependent default
+                    if !default_ty.needs_subst() {
+                        // then substitute with the default.
+                        return default_ty.into();
+                    }
                 }
+                // Mark unwanted params as err.
+                fcx.tcx.types.err.into()
             }
-            // Mark unwanted params as err.
-            fcx.tcx.types.err
-        });
+        }
+    });
     // Now we build the substituted predicates.
     for &pred in predicates.predicates.iter() {
         struct CountParams { params: FxHashSet<u32> }
@@ -638,15 +660,25 @@ fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err.emit();
 }
 
-fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
+fn reject_shadowing_parameters(tcx: TyCtxt, def_id: DefId) {
     let generics = tcx.generics_of(def_id);
     let parent = tcx.generics_of(generics.parent.unwrap());
-    let impl_params: FxHashMap<_, _> = parent.types
-                                       .iter()
-                                       .map(|tp| (tp.name, tp.def_id))
-                                       .collect();
-
-    for method_param in &generics.types {
+    let impl_params: FxHashMap<_, _> =
+        parent.params.iter()
+                     .flat_map(|param| {
+                         match param.kind {
+                             GenericParamDefKind::Lifetime => None,
+                             GenericParamDefKind::Type(_) => Some((param.name, param.def_id)),
+                         }
+                     })
+                     .collect();
+
+    for method_param in generics.params.iter() {
+        match method_param.kind {
+            // Shadowing is checked in resolve_lifetime.
+            GenericParamDefKind::Lifetime => continue,
+            _ => {},
+        };
         if impl_params.contains_key(&method_param.name) {
             // Tighten up the span to focus on only the shadowing type
             let type_span = tcx.def_span(method_param.def_id);
@@ -660,6 +692,41 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
     }
 }
 
+/// Feature gates RFC 2056 - trivial bounds, checking for global bounds that
+/// aren't true.
+fn check_false_global_bounds<'a, 'gcx, 'tcx>(
+        fcx: &FnCtxt<'a, 'gcx, 'tcx>,
+        span: Span,
+        id: ast::NodeId,
+) {
+    use rustc::ty::TypeFoldable;
+
+    let empty_env = ty::ParamEnv::empty();
+
+    let def_id = fcx.tcx.hir.local_def_id(id);
+    let predicates = fcx.tcx.predicates_of(def_id).predicates;
+    // Check elaborated bounds
+    let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
+
+    for pred in implied_obligations {
+        // Match the existing behavior.
+        if pred.is_global() && !pred.has_late_bound_regions() {
+            let obligation = traits::Obligation::new(
+                traits::ObligationCause::new(
+                    span,
+                    id,
+                    traits::TrivialBound,
+                ),
+                empty_env,
+                pred,
+            );
+            fcx.register_predicate(obligation);
+        }
+    }
+
+    fcx.select_all_obligations_or_error();
+}
+
 pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
index 57c1d33cb5d2ae608bf7d9dce6b1d4eb73f5d3aa..b0ee1154e863b37999a2f8626341a9454c6fc515 100644 (file)
@@ -593,7 +593,7 @@ fn new(
     fn report_error(&self, t: Ty<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
-                .need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t);
+                .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t).emit();
         }
     }
 }
index 3424a31e09df09245058b1315be2b9c54450c6c2..2f08a54e10f08839b6cffbb4d58899f9d42af86f 100644 (file)
@@ -111,9 +111,9 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("visit_implementation_of_copy: self_type={:?} (free)",
            self_type);
 
-    match param_env.can_type_implement_copy(tcx, self_type, span) {
+    match param_env.can_type_implement_copy(tcx, self_type) {
         Ok(()) => {}
-        Err(CopyImplementationError::InfrigingField(field)) => {
+        Err(CopyImplementationError::InfrigingFields(fields)) => {
             let item = tcx.hir.expect_item(impl_node_id);
             let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
                 tr.path.span
@@ -121,14 +121,14 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span
             };
 
-            struct_span_err!(tcx.sess,
-                             span,
-                             E0204,
-                             "the trait `Copy` may not be implemented for this type")
-                .span_label(
-                    tcx.def_span(field.did),
-                    "this field does not implement `Copy`")
-                .emit()
+            let mut err = struct_span_err!(tcx.sess,
+                                          span,
+                                          E0204,
+                                          "the trait `Copy` may not be implemented for this type");
+            for span in fields.iter().map(|f| tcx.def_span(f.did)) {
+                    err.span_label(span, "this field does not implement `Copy`");
+            }
+            err.emit()
         }
         Err(CopyImplementationError::NotAnAdt) => {
             let item = tcx.hir.expect_item(impl_node_id);
index f0f392a2458e9079389458bfd3aa7239299fb37f..c2dde2d2e014b1f7fb403adb82c5cc43e71055d5 100644 (file)
@@ -181,7 +181,7 @@ fn get_type_parameter_bounds(&self,
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
     }
 
-    fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
+    fn re_infer(&self, _span: Span, _def: Option<&ty::GenericParamDef>)
                 -> Option<ty::Region<'tcx>> {
         None
     }
@@ -243,8 +243,8 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let param_owner = tcx.hir.ty_param_owner(param_id);
     let param_owner_def_id = tcx.hir.local_def_id(param_owner);
     let generics = tcx.generics_of(param_owner_def_id);
-    let index = generics.type_param_to_index[&def_id];
-    let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_interned_str());
+    let index = generics.param_def_id_to_index[&def_id];
+    let ty = tcx.mk_ty_param(index, tcx.hir.ty_param_name(param_id).as_interned_str());
 
     // Don't look for bounds where the type parameter isn't in scope.
     let parent = if item_def_id == param_owner_def_id {
@@ -840,14 +840,16 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     // the node id for the Self type parameter.
                     let param_id = item.id;
 
-                    opt_self = Some(ty::TypeParameterDef {
+                    opt_self = Some(ty::GenericParamDef {
                         index: 0,
                         name: keywords::SelfType.name().as_interned_str(),
                         def_id: tcx.hir.local_def_id(param_id),
-                        has_default: false,
-                        object_lifetime_default: rl::Set1::Empty,
                         pure_wrt_drop: false,
-                        synthetic: None,
+                        kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+                            has_default: false,
+                            object_lifetime_default: rl::Set1::Empty,
+                            synthetic: None,
+                        }),
                     });
 
                     allow_defaults = true;
@@ -876,31 +878,33 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let has_self = opt_self.is_some();
     let mut parent_has_self = false;
     let mut own_start = has_self as u32;
-    let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
+    let parent_count = parent_def_id.map_or(0, |def_id| {
         let generics = tcx.generics_of(def_id);
         assert_eq!(has_self, false);
         parent_has_self = generics.has_self;
         own_start = generics.count() as u32;
-        (generics.parent_regions + generics.regions.len() as u32,
-            generics.parent_types + generics.types.len() as u32)
+        generics.parent_count + generics.params.len()
     });
 
+    let mut params: Vec<_> = opt_self.into_iter().collect();
+
     let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
-    let regions = early_lifetimes.enumerate().map(|(i, l)| {
-        ty::RegionParameterDef {
+    params.extend(early_lifetimes.enumerate().map(|(i, l)| {
+        ty::GenericParamDef {
             name: l.lifetime.name.name().as_interned_str(),
             index: own_start + i as u32,
             def_id: tcx.hir.local_def_id(l.lifetime.id),
             pure_wrt_drop: l.pure_wrt_drop,
+            kind: ty::GenericParamDefKind::Lifetime,
         }
-    }).collect::<Vec<_>>();
+    }));
 
     let hir_id = tcx.hir.node_to_hir_id(node_id);
     let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id);
 
     // Now create the real type parameters.
-    let type_start = own_start + regions.len() as u32;
-    let types = ast_generics.ty_params().enumerate().map(|(i, p)| {
+    let type_start = own_start - has_self as u32 + params.len() as u32;
+    params.extend(ast_generics.ty_params().enumerate().map(|(i, p)| {
         if p.name == keywords::SelfType.name() {
             span_bug!(p.span, "`Self` should not be the name of a regular parameter");
         }
@@ -916,19 +920,19 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
-        ty::TypeParameterDef {
+        ty::GenericParamDef {
             index: type_start + i as u32,
             name: p.name.as_interned_str(),
             def_id: tcx.hir.local_def_id(p.id),
-            has_default: p.default.is_some(),
-            object_lifetime_default:
-                object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
             pure_wrt_drop: p.pure_wrt_drop,
-            synthetic: p.synthetic,
+            kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+                has_default: p.default.is_some(),
+                object_lifetime_default:
+                    object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
+                synthetic: p.synthetic,
+            }),
         }
-    });
-
-    let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+    }));
 
     // provide junk type parameter defs - the only place that
     // cares about anything but the length is instantiation,
@@ -941,43 +945,45 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         };
 
         for (i, &arg) in dummy_args.iter().enumerate() {
-            types.push(ty::TypeParameterDef {
+            params.push(ty::GenericParamDef {
                 index: type_start + i as u32,
                 name: Symbol::intern(arg).as_interned_str(),
                 def_id,
-                has_default: false,
-                object_lifetime_default: rl::Set1::Empty,
                 pure_wrt_drop: false,
-                synthetic: None,
+                kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+                    has_default: false,
+                    object_lifetime_default: rl::Set1::Empty,
+                    synthetic: None,
+                }),
             });
         }
 
         tcx.with_freevars(node_id, |fv| {
-            types.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
-                ty::TypeParameterDef {
+            params.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
+                ty::GenericParamDef {
                     index: type_start + i,
                     name: Symbol::intern("<upvar>").as_interned_str(),
                     def_id,
-                    has_default: false,
-                    object_lifetime_default: rl::Set1::Empty,
                     pure_wrt_drop: false,
-                    synthetic: None,
+                    kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+                        has_default: false,
+                        object_lifetime_default: rl::Set1::Empty,
+                        synthetic: None,
+                    }),
                 }
             }));
         });
     }
 
-    let type_param_to_index = types.iter()
-                                   .map(|param| (param.def_id, param.index))
-                                   .collect();
+    let param_def_id_to_index = params.iter()
+                                      .map(|param| (param.def_id, param.index))
+                                      .collect();
 
     tcx.alloc_generics(ty::Generics {
         parent: parent_def_id,
-        parent_regions,
-        parent_types,
-        regions,
-        types,
-        type_param_to_index,
+        parent_count,
+        params,
+        param_def_id_to_index,
         has_self: has_self || parent_has_self,
         has_late_bound_regions: has_late_bound_regions(tcx, node),
     })
@@ -1090,15 +1096,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             let substs = ty::ClosureSubsts {
-                substs: Substs::for_item(
-                    tcx,
-                    def_id,
-                    |def, _| {
-                        let region = def.to_early_bound_region_data();
-                        tcx.mk_region(ty::ReEarlyBound(region))
-                    },
-                    |def, _| tcx.mk_param_from_def(def)
-                )
+                substs: Substs::identity_for_item(tcx, def_id),
             };
 
             tcx.mk_closure(def_id, substs)
@@ -1390,7 +1388,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     let generics = tcx.generics_of(def_id);
-    let parent_count = generics.parent_count() as u32;
+    let parent_count = generics.parent_count as u32;
     let has_own_self = generics.has_self && parent_count == 0;
 
     let mut predicates = vec![];
index faf3ccb1133adcb89c9a18a168d0120f8aa5a228..80dde814c6638a529eee689fc4b0e552150f37cd 100644 (file)
@@ -72,10 +72,9 @@ struct ImplWfCheck<'a, 'tcx: 'a> {
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
+            hir::ItemImpl(.., ref impl_item_refs) => {
                 let impl_def_id = self.tcx.hir.local_def_id(item.id);
                 enforce_impl_params_are_constrained(self.tcx,
-                                                    generics,
                                                     impl_def_id,
                                                     impl_item_refs);
                 enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
@@ -90,7 +89,6 @@ fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
 }
 
 fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                 impl_hir_generics: &hir::Generics,
                                                  impl_def_id: DefId,
                                                  impl_item_refs: &[hir::ImplItemRef])
 {
@@ -104,17 +102,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ctp::identify_constrained_type_params(
         tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
 
-    // Disallow ANY unconstrained type parameters.
-    for (ty_param, param) in impl_generics.types.iter().zip(impl_hir_generics.ty_params()) {
-        let param_ty = ty::ParamTy::for_def(ty_param);
-        if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
-            report_unused_parameter(tcx, param.span, "type", &param_ty.to_string());
-        }
-    }
-
     // Disallow unconstrained lifetimes, but only if they appear in assoc types.
     let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
-        .map(|item_ref|  tcx.hir.local_def_id(item_ref.id.node_id))
+        .map(|item_ref| tcx.hir.local_def_id(item_ref.id.node_id))
         .filter(|&def_id| {
             let item = tcx.associated_item(def_id);
             item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
@@ -122,17 +112,29 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         .flat_map(|def_id| {
             ctp::parameters_for(&tcx.type_of(def_id), true)
         }).collect();
-    for (ty_lifetime, lifetime) in impl_generics.regions.iter()
-        .zip(impl_hir_generics.lifetimes())
-    {
-        let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
 
-        if
-            lifetimes_in_associated_types.contains(&param) && // (*)
-            !input_parameters.contains(&param)
-        {
-            report_unused_parameter(tcx, lifetime.lifetime.span,
-                                    "lifetime", &lifetime.lifetime.name.name().to_string());
+    for param in &impl_generics.params {
+        match param.kind {
+            // Disallow ANY unconstrained type parameters.
+            ty::GenericParamDefKind::Type(_) => {
+                let param_ty = ty::ParamTy::for_def(param);
+                if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
+                    report_unused_parameter(tcx,
+                                            tcx.def_span(param.def_id),
+                                            "type",
+                                            &param_ty.to_string());
+                }
+            }
+            ty::GenericParamDefKind::Lifetime => {
+                let param_lt = ctp::Parameter::from(param.to_early_bound_region_data());
+                if lifetimes_in_associated_types.contains(&param_lt) && // (*)
+                    !input_parameters.contains(&param_lt) {
+                    report_unused_parameter(tcx,
+                                            tcx.def_span(param.def_id),
+                                            "lifetime",
+                                            &param.name.to_string());
+                }
+            }
         }
     }
 
index 5a9539a8badf01ab87a6fbd1756733f39361f0fc..e711598c944c12ba0031efe79c08b8e8f656ac47 100644 (file)
@@ -353,7 +353,7 @@ fn insert_outlives_predicate<'tcx>(
                         // Vec<U>`.  Decomposing `Vec<U>` into
                         // components would yield `U`, and we add the
                         // where clause that `U: 'a`.
-                        let ty: Ty<'tcx> = tcx.mk_param(param_ty.idx, param_ty.name);
+                        let ty: Ty<'tcx> = tcx.mk_ty_param(param_ty.idx, param_ty.name);
                         required_predicates
                             .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
                     }
index 3a376bb9affbac4462b01bf81c8b0c5209ea9b6f..96a2194eeeefda76809b53d0d986462a17ca6e71 100644 (file)
@@ -10,3 +10,4 @@ path = "lib.rs"
 [dependencies]
 pulldown-cmark = { version = "0.1.2", default-features = false }
 tempdir = "0.3"
+minifier = "0.0.11"
index 722dcb7fe6a73f750b41f3aee6ca1dd891ee8d80..d7646ce7bfc5ca4fb24dded85c7ca43bfb765438 100644 (file)
@@ -224,42 +224,39 @@ fn get_auto_trait_impl_for(
     }
 
     fn generics_to_path_params(&self, generics: ty::Generics) -> hir::PathParameters {
-        let lifetimes = HirVec::from_vec(
-            generics
-                .regions
-                .iter()
-                .map(|p| {
-                    let name = if p.name == "" {
+        let mut lifetimes = vec![];
+        let mut types = vec![];
+
+        for param in generics.params.iter() {
+            match param.kind {
+                ty::GenericParamDefKind::Lifetime => {
+                    let name = if param.name == "" {
                         hir::LifetimeName::Static
                     } else {
-                        hir::LifetimeName::Name(p.name.as_symbol())
+                        hir::LifetimeName::Name(param.name.as_symbol())
                     };
 
-                    hir::Lifetime {
+                    lifetimes.push(hir::Lifetime {
                         id: ast::DUMMY_NODE_ID,
                         span: DUMMY_SP,
                         name,
-                    }
-                })
-                .collect(),
-        );
-        let types = HirVec::from_vec(
-            generics
-                .types
-                .iter()
-                .map(|p| P(self.ty_param_to_ty(p.clone())))
-                .collect(),
-        );
+                    });
+                }
+                ty::GenericParamDefKind::Type(_) => {
+                    types.push(P(self.ty_param_to_ty(param.clone())));
+                }
+            }
+        }
 
         hir::PathParameters {
-            lifetimes: lifetimes,
-            types: types,
+            lifetimes: HirVec::from_vec(lifetimes),
+            types: HirVec::from_vec(types),
             bindings: HirVec::new(),
             parenthesized: false,
         }
     }
 
-    fn ty_param_to_ty(&self, param: ty::TypeParameterDef) -> hir::Ty {
+    fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
         debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
         hir::Ty {
             id: ast::DUMMY_NODE_ID,
@@ -494,7 +491,7 @@ fn extract_for_generics<'b, 'c, 'd>(
         &self,
         tcx: TyCtxt<'b, 'c, 'd>,
         pred: ty::Predicate<'d>,
-    ) -> FxHashSet<GenericParam> {
+    ) -> FxHashSet<GenericParamDef> {
         pred.walk_tys()
             .flat_map(|t| {
                 let mut regions = FxHashSet();
@@ -505,7 +502,7 @@ fn extract_for_generics<'b, 'c, 'd>(
                         // We only care about late bound regions, as we need to add them
                         // to the 'for<>' section
                         &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => {
-                            Some(GenericParam::Lifetime(Lifetime(name.to_string())))
+                            Some(GenericParamDef::Lifetime(Lifetime(name.to_string())))
                         }
                         &ty::ReVar(_) | &ty::ReEarlyBound(_) => None,
                         _ => panic!("Unexpected region type {:?}", r),
@@ -853,7 +850,7 @@ fn param_env_to_generics<'b, 'c, 'cx>(
 
         for p in generic_params.iter_mut() {
             match p {
-                &mut GenericParam::Type(ref mut ty) => {
+                &mut GenericParamDef::Type(ref mut ty) => {
                     // We never want something like 'impl<T=Foo>'
                     ty.default.take();
 
@@ -863,7 +860,7 @@ fn param_env_to_generics<'b, 'c, 'cx>(
                         ty.bounds.insert(0, TyParamBound::maybe_sized(self.cx));
                     }
                 }
-                _ => {}
+                GenericParamDef::Lifetime(_) => {}
             }
         }
 
index 007938e86ed9d9f37addd9624cd71b897b7c8c1a..a1d77f4145b83f19f77a2c2bcf707035fce13bb0 100644 (file)
@@ -17,7 +17,7 @@
 pub use self::TyParamBound::*;
 pub use self::SelfTy::*;
 pub use self::FunctionRetTy::*;
-pub use self::Visibility::*;
+pub use self::Visibility::{Public, Inherited};
 
 use syntax;
 use rustc_target::spec::abi::Abi;
@@ -41,7 +41,7 @@
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::hir::def_id::DefIndexAddressSpace;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
+use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind, GenericParamCount};
 use rustc::middle::stability;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_typeck::hir_ty_to_ty;
@@ -697,7 +697,7 @@ fn from_iter<T>(iter: T) -> Self
 pub struct Attributes {
     pub doc_strings: Vec<DocFragment>,
     pub other_attrs: Vec<ast::Attribute>,
-    pub cfg: Option<Rc<Cfg>>,
+    pub cfg: Option<Arc<Cfg>>,
     pub span: Option<syntax_pos::Span>,
     /// map from Rust paths to resolved defs and potential URL fragments
     pub links: Vec<(String, Option<DefId>, Option<String>)>,
@@ -848,7 +848,7 @@ pub fn from_ast(diagnostic: &::errors::Handler,
         Attributes {
             doc_strings,
             other_attrs,
-            cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
+            cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
             span: sp,
             links: vec![],
         }
@@ -1336,14 +1336,18 @@ fn clean(&self, cx: &DocContext) -> TyParam {
     }
 }
 
-impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
+impl<'tcx> Clean<TyParam> for ty::GenericParamDef {
     fn clean(&self, cx: &DocContext) -> TyParam {
         cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
+        let has_default = match self.kind {
+            ty::GenericParamDefKind::Type(ty) => ty.has_default,
+            _ => panic!("tried to convert a non-type GenericParamDef as a type")
+        };
         TyParam {
             name: self.name.clean(cx),
             did: self.def_id,
             bounds: vec![], // these are filled in from the where-clauses
-            default: if self.has_default {
+            default: if has_default {
                 Some(cx.tcx.type_of(self.def_id).clean(cx))
             } else {
                 None
@@ -1484,7 +1488,7 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
                         if let &ty::RegionKind::ReLateBound(..) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
                             if let Some(lt) = reg.clean(cx) {
-                                late_bounds.push(GenericParam::Lifetime(lt));
+                                late_bounds.push(GenericParamDef::Lifetime(lt));
                             }
                         }
                     }
@@ -1577,8 +1581,8 @@ fn clean(&self, _: &DocContext) -> Lifetime {
     }
 }
 
-impl Clean<Lifetime> for ty::RegionParameterDef {
-    fn clean(&self, _: &DocContext) -> Lifetime {
+impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
+    fn clean(&self, _cx: &DocContext) -> Lifetime {
         Lifetime(self.name.to_string())
     }
 }
@@ -1718,26 +1722,25 @@ fn clean(&self, cx: &DocContext) -> Type {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub enum GenericParam {
+pub enum GenericParamDef {
     Lifetime(Lifetime),
     Type(TyParam),
 }
 
-impl GenericParam {
+impl GenericParamDef {
     pub fn is_synthetic_type_param(&self) -> bool {
-        if let GenericParam::Type(ref t) = *self {
-            t.synthetic.is_some()
-        } else {
-            false
+        match self {
+            GenericParamDef::Type(ty) => ty.synthetic.is_some(),
+            GenericParamDef::Lifetime(_) => false,
         }
     }
 }
 
-impl Clean<GenericParam> for hir::GenericParam {
-    fn clean(&self, cx: &DocContext) -> GenericParam {
+impl Clean<GenericParamDef> for hir::GenericParam {
+    fn clean(&self, cx: &DocContext) -> GenericParamDef {
         match *self {
-            hir::GenericParam::Lifetime(ref l) => GenericParam::Lifetime(l.clean(cx)),
-            hir::GenericParam::Type(ref t) => GenericParam::Type(t.clean(cx)),
+            hir::GenericParam::Lifetime(ref l) => GenericParamDef::Lifetime(l.clean(cx)),
+            hir::GenericParam::Type(ref t) => GenericParamDef::Type(t.clean(cx)),
         }
     }
 }
@@ -1745,7 +1748,7 @@ fn clean(&self, cx: &DocContext) -> GenericParam {
 // maybe use a Generic enum and use Vec<Generic>?
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
 pub struct Generics {
-    pub params: Vec<GenericParam>,
+    pub params: Vec<GenericParamDef>,
     pub where_predicates: Vec<WherePredicate>,
 }
 
@@ -1754,7 +1757,7 @@ fn clean(&self, cx: &DocContext) -> Generics {
         let mut params = Vec::with_capacity(self.params.len());
         for p in &self.params {
             let p = p.clean(cx);
-            if let GenericParam::Type(ref tp) = p {
+            if let GenericParamDef::Type(ref tp) = p {
                 if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
                     cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone());
                 }
@@ -1774,7 +1777,7 @@ fn clean(&self, cx: &DocContext) -> Generics {
                 WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
                     if bounds.is_empty() {
                         for param in &mut g.params {
-                            if let GenericParam::Type(ref mut type_param) = *param {
+                            if let GenericParamDef::Type(ref mut type_param) = *param {
                                 if &type_param.name == name {
                                     mem::swap(bounds, &mut type_param.bounds);
                                     break
@@ -1800,14 +1803,18 @@ fn clean(&self, cx: &DocContext) -> Generics {
         // Bounds in the type_params and lifetimes fields are repeated in the
         // predicates field (see rustc_typeck::collect::ty_generics), so remove
         // them.
-        let stripped_typarams = gens.types.iter().filter_map(|tp| {
-            if tp.name == keywords::SelfType.name().as_str() {
-                assert_eq!(tp.index, 0);
-                None
+        let stripped_typarams = gens.params.iter().filter_map(|param| {
+            if let ty::GenericParamDefKind::Type(_) = param.kind {
+                if param.name == keywords::SelfType.name().as_str() {
+                    assert_eq!(param.index, 0);
+                    None
+                } else {
+                    Some(param.clean(cx))
+                }
             } else {
-                Some(tp.clean(cx))
+                None
             }
-        }).collect::<Vec<_>>();
+        }).collect::<Vec<TyParam>>();
 
         let mut where_predicates = preds.predicates.to_vec().clean(cx);
 
@@ -1849,16 +1856,20 @@ fn clean(&self, cx: &DocContext) -> Generics {
         // and instead see `where T: Foo + Bar + Sized + 'a`
 
         Generics {
-            params: gens.regions
-                .clean(cx)
-                .into_iter()
-                .map(|lp| GenericParam::Lifetime(lp))
-                .chain(
-                    simplify::ty_params(stripped_typarams)
-                        .into_iter()
-                        .map(|tp| GenericParam::Type(tp))
-                )
-                .collect(),
+            params: gens.params
+                        .iter()
+                        .flat_map(|param| {
+                            if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                Some(GenericParamDef::Lifetime(param.clean(cx)))
+                            } else {
+                                None
+                            }
+                        }).chain(
+                            simplify::ty_params(stripped_typarams)
+                                .into_iter()
+                                .map(|tp| GenericParamDef::Type(tp))
+                        )
+                        .collect(),
             where_predicates: simplify::where_clauses(cx, where_predicates),
         }
     }
@@ -2349,7 +2360,7 @@ fn clean(&self, cx: &DocContext) -> Item {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub struct PolyTrait {
     pub trait_: Type,
-    pub generic_params: Vec<GenericParam>,
+    pub generic_params: Vec<GenericParamDef>,
 }
 
 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
@@ -2644,10 +2655,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     promoted: None
                 };
                 let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
-                    cx.tcx.mk_const(ty::Const {
-                        val: ConstVal::Unevaluated(def_id, substs),
-                        ty: cx.tcx.types.usize
-                    })
+                    ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
                 });
                 let n = print_const(cx, n);
                 Array(box ty.clean(cx), n)
@@ -2679,20 +2687,34 @@ fn clean(&self, cx: &DocContext) -> Type {
                     let mut ty_substs = FxHashMap();
                     let mut lt_substs = FxHashMap();
                     provided_params.with_parameters(|provided_params| {
-                        for (i, ty_param) in generics.ty_params().enumerate() {
-                            let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
-                            if let Some(ty) = provided_params.types.get(i).cloned() {
-                                ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
-                            } else if let Some(default) = ty_param.default.clone() {
-                                ty_substs.insert(ty_param_def, default.into_inner().clean(cx));
-                            }
-                        }
-
-                        for (i, lt_param) in generics.lifetimes().enumerate() {
-                            if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
-                                if !lt.is_elided() {
-                                    let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
-                                    lt_substs.insert(lt_def_id, lt.clean(cx));
+                        let mut indices = GenericParamCount {
+                            lifetimes: 0,
+                            types: 0
+                        };
+                        for param in generics.params.iter() {
+                            match param {
+                                hir::GenericParam::Lifetime(lt_param) => {
+                                    if let Some(lt) = provided_params.lifetimes
+                                        .get(indices.lifetimes).cloned() {
+                                        if !lt.is_elided() {
+                                            let lt_def_id =
+                                                cx.tcx.hir.local_def_id(lt_param.lifetime.id);
+                                            lt_substs.insert(lt_def_id, lt.clean(cx));
+                                        }
+                                    }
+                                    indices.lifetimes += 1;
+                                }
+                                hir::GenericParam::Type(ty_param) => {
+                                    let ty_param_def =
+                                        Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
+                                    if let Some(ty) = provided_params.types
+                                        .get(indices.types).cloned() {
+                                        ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
+                                    } else if let Some(default) = ty_param.default.clone() {
+                                        ty_substs.insert(ty_param_def,
+                                                         default.into_inner().clean(cx));
+                                    }
+                                    indices.types += 1;
                                 }
                             }
                         }
@@ -2976,11 +2998,22 @@ fn clean(&self, cx: &DocContext) -> Item {
 pub enum Visibility {
     Public,
     Inherited,
+    Crate,
+    Restricted(DefId, Path),
 }
 
 impl Clean<Option<Visibility>> for hir::Visibility {
-    fn clean(&self, _: &DocContext) -> Option<Visibility> {
-        Some(if *self == hir::Visibility::Public { Public } else { Inherited })
+    fn clean(&self, cx: &DocContext) -> Option<Visibility> {
+        Some(match *self {
+            hir::Visibility::Public => Visibility::Public,
+            hir::Visibility::Inherited => Visibility::Inherited,
+            hir::Visibility::Crate => Visibility::Crate,
+            hir::Visibility::Restricted { ref path, .. } => {
+                let path = path.clean(cx);
+                let did = register_def(cx, path.def);
+                Visibility::Restricted(did, path)
+            }
+        })
     }
 }
 
@@ -3417,7 +3450,7 @@ fn clean(&self, cx: &DocContext) -> Item {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub struct BareFunctionDecl {
     pub unsafety: hir::Unsafety,
-    pub generic_params: Vec<GenericParam>,
+    pub generic_params: Vec<GenericParamDef>,
     pub decl: FnDecl,
     pub abi: Abi,
 }
@@ -3828,9 +3861,9 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String {
                 inline::print_inlined_const(cx, def_id)
             }
         },
-        ConstVal::Value(val) => {
+        ConstVal::Value(..) => {
             let mut s = String::new();
-            ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
+            ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
             // array lengths are obviously usize
             if s.ends_with("usize") {
                 let n = s.len() - "usize".len();
@@ -4176,7 +4209,7 @@ struct RegionDeps<'tcx> {
 #[derive(Eq, PartialEq, Hash, Debug)]
 enum SimpleBound {
     RegionBound(Lifetime),
-    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParam>, hir::TraitBoundModifier)
+    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier)
 }
 
 enum AutoTraitResult {
index 61fb0b40c231560b8005af5f1997b706a41f190e..c9a80d4779177bed04d448da3b747f940b408c61 100644 (file)
@@ -117,6 +117,57 @@ fn is_doc_reachable(&self, did: DefId) -> bool {
     }
 }
 
+/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
+///
+/// If the given `error_format` is `ErrorOutputType::Json` and no `CodeMap` is given, a new one
+/// will be created for the handler.
+pub fn new_handler(error_format: ErrorOutputType, codemap: Option<Lrc<codemap::CodeMap>>)
+    -> errors::Handler
+{
+    // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
+    // stick to the defaults
+    let sessopts = config::basic_options();
+    let emitter: Box<dyn Emitter + sync::Send> = match error_format {
+        ErrorOutputType::HumanReadable(color_config) => Box::new(
+            EmitterWriter::stderr(
+                color_config,
+                codemap.map(|cm| cm as _),
+                false,
+                sessopts.debugging_opts.teach,
+            ).ui_testing(sessopts.debugging_opts.ui_testing)
+        ),
+        ErrorOutputType::Json(pretty) => {
+            let codemap = codemap.unwrap_or_else(
+                || Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())));
+            Box::new(
+                JsonEmitter::stderr(
+                    None,
+                    codemap,
+                    pretty,
+                    sessopts.debugging_opts.suggestion_applicability,
+                ).ui_testing(sessopts.debugging_opts.ui_testing)
+            )
+        },
+        ErrorOutputType::Short(color_config) => Box::new(
+            EmitterWriter::stderr(
+                color_config,
+                codemap.map(|cm| cm as _),
+                true,
+                false)
+        ),
+    };
+
+    errors::Handler::with_emitter_and_flags(
+        emitter,
+        errors::HandlerFlags {
+            can_emit_warnings: true,
+            treat_err_as_bug: false,
+            external_macro_backtrace: false,
+            ..Default::default()
+        },
+    )
+}
+
 pub fn run_core(search_paths: SearchPaths,
                 cfgs: Vec<String>,
                 externs: config::Externs,
@@ -159,163 +210,134 @@ pub fn run_core(search_paths: SearchPaths,
         },
         error_format,
         edition,
-        ..config::basic_options().clone()
+        ..config::basic_options()
     };
-
-    let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
-    let emitter: Box<dyn Emitter + sync::Send> = match error_format {
-        ErrorOutputType::HumanReadable(color_config) => Box::new(
-            EmitterWriter::stderr(
-                color_config,
-                Some(codemap.clone()),
-                false,
-                sessopts.debugging_opts.teach,
-            ).ui_testing(sessopts.debugging_opts.ui_testing)
-        ),
-        ErrorOutputType::Json(pretty) => Box::new(
-            JsonEmitter::stderr(
-                None,
-                codemap.clone(),
-                pretty,
-                sessopts.debugging_opts.suggestion_applicability,
-            ).ui_testing(sessopts.debugging_opts.ui_testing)
-        ),
-        ErrorOutputType::Short(color_config) => Box::new(
-            EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
-        ),
-    };
-
-    let diagnostic_handler = errors::Handler::with_emitter_and_flags(
-        emitter,
-        errors::HandlerFlags {
-            can_emit_warnings: true,
-            treat_err_as_bug: false,
-            external_macro_backtrace: false,
-            ..Default::default()
-        },
-    );
-
-    let mut sess = session::build_session_(
-        sessopts, cpath, diagnostic_handler, codemap,
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let control = &driver::CompileController::basic();
-
-    let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
-
-    let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
-
-    let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
-
-    let resolver_arenas = resolve::Resolver::arenas();
-    let result = driver::phase_2_configure_and_expand_inner(&sess,
-                                                      &cstore,
-                                                      krate,
-                                                      None,
-                                                      &name,
-                                                      None,
-                                                      resolve::MakeGlobMap::No,
-                                                      &resolver_arenas,
-                                                      &mut crate_loader,
-                                                      |_| Ok(()));
-    let driver::InnerExpansionResult {
-        mut hir_forest,
-        resolver,
-        ..
-    } = abort_on_err(result, &sess);
-
-    // We need to hold on to the complete resolver, so we clone everything
-    // for the analysis passes to use. Suboptimal, but necessary in the
-    // current architecture.
-    let defs = resolver.definitions.clone();
-    let resolutions = ty::Resolutions {
-        freevars: resolver.freevars.clone(),
-        export_map: resolver.export_map.clone(),
-        trait_map: resolver.trait_map.clone(),
-        maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
-        maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
-    };
-    let analysis = ty::CrateAnalysis {
-        access_levels: Lrc::new(AccessLevels::default()),
-        name: name.to_string(),
-        glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
-    };
-
-    let arenas = AllArenas::new();
-    let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
-    let output_filenames = driver::build_output_filenames(&input,
-                                                          &None,
-                                                          &None,
-                                                          &[],
-                                                          &sess);
-
-    let resolver = RefCell::new(resolver);
-
-    abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
-                                                     control,
-                                                     &sess,
-                                                     &*cstore,
-                                                     hir_map,
-                                                     analysis,
-                                                     resolutions,
-                                                     &arenas,
-                                                     &name,
-                                                     &output_filenames,
-                                                     |tcx, analysis, _, result| {
-        if let Err(_) = result {
-            sess.fatal("Compilation failed, aborting rustdoc");
-        }
-
-        let ty::CrateAnalysis { access_levels, .. } = analysis;
-
-        // Convert from a NodeId set to a DefId set since we don't always have easy access
-        // to the map from defid -> nodeid
-        let access_levels = AccessLevels {
-            map: access_levels.map.iter()
-                                  .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
-                                  .collect()
-        };
-
-        let send_trait = if crate_name == Some("core".to_string()) {
-            clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
-        } else {
-            clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+    driver::spawn_thread_pool(sessopts, move |sessopts| {
+        let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
+        let diagnostic_handler = new_handler(error_format, Some(codemap.clone()));
+
+        let mut sess = session::build_session_(
+            sessopts, cpath, diagnostic_handler, codemap,
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = Rc::new(CStore::new(trans.metadata_loader()));
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let control = &driver::CompileController::basic();
+
+        let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
+
+        let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+
+        let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
+
+        let resolver_arenas = resolve::Resolver::arenas();
+        let result = driver::phase_2_configure_and_expand_inner(&sess,
+                                                        &cstore,
+                                                        krate,
+                                                        None,
+                                                        &name,
+                                                        None,
+                                                        resolve::MakeGlobMap::No,
+                                                        &resolver_arenas,
+                                                        &mut crate_loader,
+                                                        |_| Ok(()));
+        let driver::InnerExpansionResult {
+            mut hir_forest,
+            resolver,
+            ..
+        } = abort_on_err(result, &sess);
+
+        // We need to hold on to the complete resolver, so we clone everything
+        // for the analysis passes to use. Suboptimal, but necessary in the
+        // current architecture.
+        let defs = resolver.definitions.clone();
+        let resolutions = ty::Resolutions {
+            freevars: resolver.freevars.clone(),
+            export_map: resolver.export_map.clone(),
+            trait_map: resolver.trait_map.clone(),
+            maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
+            maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
         };
-
-        let ctxt = DocContext {
-            tcx,
-            resolver: &resolver,
-            crate_name,
-            cstore: cstore.clone(),
-            populated_all_crate_impls: Cell::new(false),
-            access_levels: RefCell::new(access_levels),
-            external_traits: Default::default(),
-            active_extern_traits: Default::default(),
-            renderinfo: Default::default(),
-            ty_substs: Default::default(),
-            lt_substs: Default::default(),
-            impl_trait_bounds: Default::default(),
-            mod_ids: Default::default(),
-            send_trait: send_trait,
-            fake_def_ids: RefCell::new(FxHashMap()),
-            all_fake_def_ids: RefCell::new(FxHashSet()),
-            generated_synthetics: RefCell::new(FxHashSet()),
-        };
-        debug!("crate: {:?}", tcx.hir.krate());
-
-        let krate = {
-            let mut v = RustdocVisitor::new(&*cstore, &ctxt);
-            v.visit(tcx.hir.krate());
-            v.clean(&ctxt)
+        let analysis = ty::CrateAnalysis {
+            access_levels: Lrc::new(AccessLevels::default()),
+            name: name.to_string(),
+            glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
         };
 
-        (krate, ctxt.renderinfo.into_inner())
-    }), &sess)
+        let arenas = AllArenas::new();
+        let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
+        let output_filenames = driver::build_output_filenames(&input,
+                                                            &None,
+                                                            &None,
+                                                            &[],
+                                                            &sess);
+
+        let resolver = RefCell::new(resolver);
+
+        abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+                                                        control,
+                                                        &sess,
+                                                        &*cstore,
+                                                        hir_map,
+                                                        analysis,
+                                                        resolutions,
+                                                        &arenas,
+                                                        &name,
+                                                        &output_filenames,
+                                                        |tcx, analysis, _, result| {
+            if let Err(_) = result {
+                sess.fatal("Compilation failed, aborting rustdoc");
+            }
+
+            let ty::CrateAnalysis { access_levels, .. } = analysis;
+
+            // Convert from a NodeId set to a DefId set since we don't always have easy access
+            // to the map from defid -> nodeid
+            let access_levels = AccessLevels {
+                map: access_levels.map.iter()
+                                    .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
+                                    .collect()
+            };
+
+            let send_trait = if crate_name == Some("core".to_string()) {
+                clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
+            } else {
+                clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+            };
+
+            let ctxt = DocContext {
+                tcx,
+                resolver: &resolver,
+                crate_name,
+                cstore: cstore.clone(),
+                populated_all_crate_impls: Cell::new(false),
+                access_levels: RefCell::new(access_levels),
+                external_traits: Default::default(),
+                active_extern_traits: Default::default(),
+                renderinfo: Default::default(),
+                ty_substs: Default::default(),
+                lt_substs: Default::default(),
+                impl_trait_bounds: Default::default(),
+                mod_ids: Default::default(),
+                send_trait: send_trait,
+                fake_def_ids: RefCell::new(FxHashMap()),
+                all_fake_def_ids: RefCell::new(FxHashSet()),
+                generated_synthetics: RefCell::new(FxHashSet()),
+            };
+            debug!("crate: {:?}", tcx.hir.krate());
+
+            let krate = {
+                let mut v = RustdocVisitor::new(&*cstore, &ctxt);
+                v.visit(tcx.hir.krate());
+                v.clean(&ctxt)
+            };
+
+            (krate, ctxt.renderinfo.into_inner())
+        }), &sess)
+    })
 }
index 6c328a87208aa73c211502192d1ad7273899bb6d..10b6c9850ae7773dc99d20972ce918c9f42570cc 100644 (file)
@@ -11,6 +11,7 @@
 use std::fs;
 use std::path::Path;
 use std::str;
+use errors;
 use html::markdown::Markdown;
 
 #[derive(Clone)]
@@ -28,23 +29,23 @@ pub struct ExternalHtml {
 
 impl ExternalHtml {
     pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
-                md_before_content: &[String], md_after_content: &[String])
+                md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler)
             -> Option<ExternalHtml> {
-        load_external_files(in_header)
+        load_external_files(in_header, diag)
             .and_then(|ih|
-                load_external_files(before_content)
+                load_external_files(before_content, diag)
                     .map(|bc| (ih, bc))
             )
             .and_then(|(ih, bc)|
-                load_external_files(md_before_content)
+                load_external_files(md_before_content, diag)
                     .map(|m_bc| (ih, format!("{}{}", bc, Markdown(&m_bc, &[]))))
             )
             .and_then(|(ih, bc)|
-                load_external_files(after_content)
+                load_external_files(after_content, diag)
                     .map(|ac| (ih, bc, ac))
             )
             .and_then(|(ih, bc, ac)|
-                load_external_files(md_after_content)
+                load_external_files(md_after_content, diag)
                     .map(|m_ac| (ih, bc, format!("{}{}", ac, Markdown(&m_ac, &[]))))
             )
             .map(|(ih, bc, ac)|
@@ -62,28 +63,30 @@ pub enum LoadStringError {
     BadUtf8,
 }
 
-pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
+pub fn load_string<P: AsRef<Path>>(file_path: P, diag: &errors::Handler)
+    -> Result<String, LoadStringError>
+{
     let file_path = file_path.as_ref();
     let contents = match fs::read(file_path) {
         Ok(bytes) => bytes,
         Err(e) => {
-            eprintln!("error reading `{}`: {}", file_path.display(), e);
+            diag.struct_err(&format!("error reading `{}`: {}", file_path.display(), e)).emit();
             return Err(LoadStringError::ReadFail);
         }
     };
     match str::from_utf8(&contents) {
         Ok(s) => Ok(s.to_string()),
         Err(_) => {
-            eprintln!("error reading `{}`: not UTF-8", file_path.display());
+            diag.struct_err(&format!("error reading `{}`: not UTF-8", file_path.display())).emit();
             Err(LoadStringError::BadUtf8)
         }
     }
 }
 
-fn load_external_files(names: &[String]) -> Option<String> {
+fn load_external_files(names: &[String], diag: &errors::Handler) -> Option<String> {
     let mut out = String::new();
     for name in names {
-        let s = match load_string(name) {
+        let s = match load_string(name, diag) {
             Ok(s) => s,
             Err(_) => return None,
         };
index a9a4c5113747ec685f80ce7c6f74ef4097a3a669..40dcd6e891fe8cfba1161c4335c4fd7c33c2b580 100644 (file)
@@ -117,11 +117,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Display for clean::GenericParam {
+impl fmt::Display for clean::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            clean::GenericParam::Lifetime(ref lp) => write!(f, "{}", lp),
-            clean::GenericParam::Type(ref tp) => {
+            clean::GenericParamDef::Lifetime(ref lp) => write!(f, "{}", lp),
+            clean::GenericParamDef::Type(ref tp) => {
                 f.write_str(&tp.name)?;
 
                 if !tp.bounds.is_empty() {
@@ -927,8 +927,19 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl<'a> fmt::Display for VisSpace<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.get() {
-            Some(clean::Public) => write!(f, "pub "),
-            Some(clean::Inherited) | None => Ok(())
+            Some(clean::Public) => f.write_str("pub "),
+            Some(clean::Inherited) | None => Ok(()),
+            Some(clean::Visibility::Crate) => write!(f, "pub(crate) "),
+            Some(clean::Visibility::Restricted(did, ref path)) => {
+                f.write_str("pub(")?;
+                if path.segments.len() != 1
+                    || (path.segments[0].name != "self" && path.segments[0].name != "super")
+                {
+                    f.write_str("in ")?;
+                }
+                resolved_path(f, did, path, true, false)?;
+                f.write_str(") ")
+            }
         }
     }
 }
index cfa3f5a4e0b4f259ac03990b0892c0b0822377b0..cff89b03e3d8b3532638c76f40aa45e3dea46357 100644 (file)
@@ -353,7 +353,7 @@ fn write_token<W: Writer>(&mut self,
             token::Lifetime(..) => Class::Lifetime,
 
             token::Eof | token::Interpolated(..) |
-            token::Tilde | token::At | token::DotEq => Class::None,
+            token::Tilde | token::At | token::DotEq | token::SingleQuote => Class::None,
         };
 
         // Anything that didn't return above is the simple case where we the
index 21de2db1dfe74fd7bf1930e06b38b3e20589b31b..109765b6711979899ac0513fe7a0990609101249 100644 (file)
@@ -76,6 +76,8 @@
 use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
 use html::{highlight, layout};
 
+use minifier;
+
 /// A pair of name and its optional document.
 pub type NameDoc = (String, Option<String>);
 
@@ -413,9 +415,9 @@ fn to_json(&self) -> Json {
         match self.name {
             Some(ref name) => {
                 let mut data = BTreeMap::new();
-                data.insert("name".to_owned(), name.to_json());
+                data.insert("n".to_owned(), name.to_json());
                 if let Some(ref generics) = self.generics {
-                    data.insert("generics".to_owned(), generics.to_json());
+                    data.insert("g".to_owned(), generics.to_json());
                 }
                 Json::Object(data)
             },
@@ -438,8 +440,12 @@ fn to_json(&self) -> Json {
             Json::Null
         } else {
             let mut data = BTreeMap::new();
-            data.insert("inputs".to_owned(), self.inputs.to_json());
-            data.insert("output".to_owned(), self.output.to_json());
+            if !self.inputs.is_empty() {
+                data.insert("i".to_owned(), self.inputs.to_json());
+            }
+            if let Some(ref output) = self.output {
+                data.insert("o".to_owned(), output.to_json());
+            }
             Json::Object(data)
         }
     }
@@ -509,7 +515,8 @@ pub fn run(mut krate: clean::Crate,
            css_file_extension: Option<PathBuf>,
            renderinfo: RenderInfo,
            sort_modules_alphabetically: bool,
-           themes: Vec<PathBuf>) -> Result<(), Error> {
+           themes: Vec<PathBuf>,
+           enable_minification: bool) -> Result<(), Error> {
     let src_root = match krate.src {
         FileName::Real(ref p) => match p.parent() {
             Some(p) => p.to_path_buf(),
@@ -661,7 +668,7 @@ pub fn run(mut krate: clean::Crate,
     CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
     CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
 
-    write_shared(&cx, &krate, &*cache, index)?;
+    write_shared(&cx, &krate, &*cache, index, enable_minification)?;
 
     // And finally render the whole crate's documentation
     cx.krate(krate)
@@ -740,7 +747,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
 fn write_shared(cx: &Context,
                 krate: &clean::Crate,
                 cache: &Cache,
-                search_index: String) -> Result<(), Error> {
+                search_index: String,
+                enable_minification: bool) -> Result<(), Error> {
     // Write out the shared files. Note that these are shared among all rustdoc
     // docs placed in the output directory, so this needs to be a synchronized
     // operation with respect to all other rustdocs running around.
@@ -789,7 +797,8 @@ fn write_shared(cx: &Context,
           format!(
 r#"var themes = document.getElementById("theme-choices");
 var themePicker = document.getElementById("theme-picker");
-themePicker.onclick = function() {{
+
+function switchThemeButtonState() {{
     if (themes.style.display === "block") {{
         themes.style.display = "none";
         themePicker.style.borderBottomRightRadius = "3px";
@@ -800,12 +809,29 @@ fn write_shared(cx: &Context,
         themePicker.style.borderBottomLeftRadius = "0";
     }}
 }};
+
+function handleThemeButtonsBlur(e) {{
+    var active = document.activeElement;
+    var related = e.relatedTarget;
+
+    if (active.id !== "themePicker" &&
+        (!active.parentNode || active.parentNode.id !== "theme-choices") &&
+        (!related ||
+         (related.id !== "themePicker" &&
+          (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{
+        switchThemeButtonState();
+    }}
+}}
+
+themePicker.onclick = switchThemeButtonState;
+themePicker.onblur = handleThemeButtonsBlur;
 [{}].forEach(function(item) {{
     var but = document.createElement('button');
     but.innerHTML = item;
     but.onclick = function(el) {{
         switchTheme(currentTheme, mainTheme, item);
     }};
+    but.onblur = handleThemeButtonsBlur;
     themes.appendChild(but);
 }});"#,
                  themes.iter()
@@ -814,16 +840,20 @@ fn write_shared(cx: &Context,
                        .join(",")).as_bytes(),
     )?;
 
-    write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
-                      include_bytes!("static/main.js"))?;
-    write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
-                      include_bytes!("static/settings.js"))?;
+    write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
+                 include_str!("static/main.js"),
+                 enable_minification)?;
+    write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
+                 include_str!("static/settings.js"),
+                 enable_minification)?;
 
     {
         let mut data = format!("var resourcesSuffix = \"{}\";\n",
-                               cx.shared.resource_suffix).into_bytes();
-        data.extend_from_slice(include_bytes!("static/storage.js"));
-        write(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), &data)?;
+                               cx.shared.resource_suffix);
+        data.push_str(include_str!("static/storage.js"));
+        write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
+                     &data,
+                     enable_minification)?;
     }
 
     if let Some(ref css) = cx.shared.css_file_extension {
@@ -879,8 +909,8 @@ fn collect(path: &Path, krate: &str, key: &str) -> io::Result<Vec<String>> {
     }
 
     fn show_item(item: &IndexItem, krate: &str) -> String {
-        format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}",
-                krate, item.ty as usize, item.name, item.path,
+        format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}",
+                krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path,
                 if let Some(p) = item.parent_idx {
                     format!(",'parent':{}", p)
                 } else {
@@ -1020,6 +1050,14 @@ fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> {
     Ok(try_err!(fs::write(&dst, contents), &dst))
 }
 
+fn write_minify(dst: PathBuf, contents: &str, enable_minification: bool) -> Result<(), Error> {
+    if enable_minification {
+        write(dst, minifier::js::minify(contents).as_bytes())
+    } else {
+        write(dst, contents.as_bytes())
+    }
+}
+
 /// Takes a path to a source file and cleans the path to it. This canonicalizes
 /// things like ".." to components which preserve the "top down" hierarchy of a
 /// static HTML tree. Each component in the cleaned path will be passed as an
@@ -1415,8 +1453,11 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 impl<'a> Cache {
     fn generics(&mut self, generics: &clean::Generics) {
         for param in &generics.params {
-            if let clean::GenericParam::Type(ref typ) = *param {
-                self.typarams.insert(typ.did, typ.name.clone());
+            match *param {
+                clean::GenericParamDef::Type(ref typ) => {
+                    self.typarams.insert(typ.did, typ.name.clone());
+                }
+                clean::GenericParamDef::Lifetime(_) => {}
             }
         }
     }
@@ -1442,7 +1483,7 @@ fn add_aliases(&mut self, item: &clean::Item) {
                                 ty: item.type_(),
                                 name: item_name.to_string(),
                                 path: path.clone(),
-                                desc: String::new(),
+                                desc: plain_summary_line(item.doc_value()),
                                 parent: None,
                                 parent_idx: None,
                                 search_type: get_index_search_type(&item),
@@ -2579,7 +2620,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 }
 
 fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
-                      implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> {
+                      implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result {
     write!(w, "<li><table class='table-display'><tbody><tr><td><code>")?;
     // If there's already another implementor that has the same abbridged name, use the
     // full path, for example in `std::iter::ExactSizeIterator`
@@ -2612,7 +2653,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
 
 fn render_impls(cx: &Context, w: &mut fmt::Formatter,
                 traits: &[&&Impl],
-                containing_item: &clean::Item) -> Result<(), fmt::Error> {
+                containing_item: &clean::Item) -> fmt::Result {
     for i in traits {
         let did = i.trait_did().unwrap();
         let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
index 8569abeb09cc1ffc800b2cf86bf1f2daee4b3878..e0235bfc6945c38bf304ee47ee78423c1092c270 100644 (file)
             return this.indexOf(searchString, position) === position;
         };
     }
+    if (!String.prototype.endsWith) {
+        String.prototype.endsWith = function(suffix, length) {
+            var l = length || this.length;
+            return this.indexOf(suffix, l - suffix.length) !== -1;
+        };
+    }
 
     function getPageId() {
         var id = document.location.href.split('#')[1];
                 onEach(e.getElementsByTagName('span'), function(i_e) {
                     removeClass(i_e, 'line-highlighted');
                 });
-            })
+            });
             for (i = from; i <= to; ++i) {
                 addClass(document.getElementById(i), 'line-highlighted');
             }
                         var obj = searchIndex[results[i].id];
                         obj.lev = results[i].lev;
                         if (isType !== true || obj.type) {
+                            var res = buildHrefAndPath(obj);
+                            obj.displayPath = pathSplitter(res[0]);
+                            obj.fullPath = obj.displayPath + obj.name;
+                            obj.href = res[1];
                             out.push(obj);
+                            if (out.length >= MAX_RESULTS) {
+                                break;
+                            }
                         }
                     }
-                    if (out.length >= MAX_RESULTS) {
-                        break;
-                    }
                 }
                 return out;
             }
                 // match as well.
                 var lev_distance = MAX_LEV_DISTANCE + 1;
                 if (val.generics.length > 0) {
-                    if (obj.generics && obj.generics.length >= val.generics.length) {
-                        var elems = obj.generics.slice(0);
+                    if (obj.g && obj.g.length >= val.generics.length) {
+                        var elems = obj.g.slice(0);
                         var total = 0;
                         var done = 0;
                         // We need to find the type that matches the most to remove it in order
             // Check for type name and type generics (if any).
             function checkType(obj, val, literalSearch) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
-                if (obj.name === val.name) {
+                if (obj.n === val.name) {
                     if (literalSearch === true) {
                         if (val.generics && val.generics.length !== 0) {
-                            if (obj.generics && obj.length >= val.generics.length) {
-                                var elems = obj.generics.slice(0);
+                            if (obj.g && obj.length >= val.generics.length) {
+                                var elems = obj.g.slice(0);
                                 var allFound = true;
                                 var x;
 
                     }
                     // If the type has generics but don't match, then it won't return at this point.
                     // Otherwise, `checkGenerics` will return 0 and it'll return.
-                    if (obj.generics && obj.generics.length !== 0) {
+                    if (obj.g && obj.g.length !== 0) {
                         var tmp_lev = checkGenerics(obj, val);
                         if (tmp_lev <= MAX_LEV_DISTANCE) {
                             return tmp_lev;
                 }
                 // Names didn't match so let's check if one of the generic types could.
                 if (literalSearch === true) {
-                     if (obj.generics && obj.generics.length > 0) {
-                        for (var x = 0; x < obj.generics.length; ++x) {
-                            if (obj.generics[x] === val.name) {
+                     if (obj.g && obj.g.length > 0) {
+                        for (var x = 0; x < obj.g.length; ++x) {
+                            if (obj.g[x] === val.name) {
                                 return true;
                             }
                         }
                     }
                     return false;
                 }
-                var lev_distance = Math.min(levenshtein(obj.name, val.name), lev_distance);
+                var lev_distance = Math.min(levenshtein(obj.n, val.name), lev_distance);
                 if (lev_distance <= MAX_LEV_DISTANCE) {
                     lev_distance = Math.min(checkGenerics(obj, val), lev_distance);
-                } else if (obj.generics && obj.generics.length > 0) {
+                } else if (obj.g && obj.g.length > 0) {
                     // We can check if the type we're looking for is inside the generics!
-                    for (var x = 0; x < obj.generics.length; ++x) {
-                        lev_distance = Math.min(levenshtein(obj.generics[x], val.name),
+                    for (var x = 0; x < obj.g.length; ++x) {
+                        lev_distance = Math.min(levenshtein(obj.g[x], val.name),
                                                 lev_distance);
                     }
                 }
             function findArg(obj, val, literalSearch) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
 
-                if (obj && obj.type && obj.type.inputs.length > 0) {
-                    for (var i = 0; i < obj.type.inputs.length; i++) {
-                        var tmp = checkType(obj.type.inputs[i], val, literalSearch);
+                if (obj && obj.type && obj.type.i && obj.type.i.length > 0) {
+                    for (var i = 0; i < obj.type.i.length; i++) {
+                        var tmp = checkType(obj.type.i[i], val, literalSearch);
                         if (literalSearch === true && tmp === true) {
                             return true;
                         }
             function checkReturned(obj, val, literalSearch) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
 
-                if (obj && obj.type && obj.type.output) {
-                    var tmp = checkType(obj.type.output, val, literalSearch);
+                if (obj && obj.type && obj.type.o) {
+                    var tmp = checkType(obj.type.o, val, literalSearch);
                     if (literalSearch === true && tmp === true) {
                         return true;
                     }
                     var fullId = generateId(ty);
 
                     // allow searching for void (no output) functions as well
-                    var typeOutput = type.output ? type.output.name : "";
+                    var typeOutput = type.o ? type.o.name : "";
                     var returned = checkReturned(ty, output, true);
                     if (output.name === "*" || returned === true) {
                         var in_args = false;
                     ALIASES[window.currentCrate][query.raw]) {
                 var aliases = ALIASES[window.currentCrate][query.raw];
                 for (var i = 0; i < aliases.length; ++i) {
+                    aliases[i].is_alias = true;
+                    aliases[i].alias = query.raw;
+                    aliases[i].path = aliases[i].p;
+                    var res = buildHrefAndPath(aliases[i]);
+                    aliases[i].displayPath = pathSplitter(res[0]);
+                    aliases[i].fullPath = aliases[i].displayPath + aliases[i].name;
+                    aliases[i].href = res[1];
                     ret['others'].unshift(aliases[i]);
                     if (ret['others'].length > MAX_RESULTS) {
                         ret['others'].pop();
             };
         }
 
-        function escape(content) {
-            var h1 = document.createElement('h1');
-            h1.textContent = content;
-            return h1.innerHTML;
-        }
-
-        function pathSplitter(path) {
-            return '<span>' + path.replace(/::/g, '::</span><span>');
-        }
-
         function buildHrefAndPath(item) {
             var displayPath;
             var href;
             return [displayPath, href];
         }
 
+        function escape(content) {
+            var h1 = document.createElement('h1');
+            h1.textContent = content;
+            return h1.innerHTML;
+        }
+
+        function pathSplitter(path) {
+            var tmp = '<span>' + path.replace(/::/g, '::</span><span>');
+            if (tmp.endsWith("<span>")) {
+                return tmp.slice(0, tmp.length - 6);
+            }
+            return tmp;
+        }
+
         function addTab(array, query, display) {
             var extraStyle = '';
             if (display === false) {
             }
 
             var output = '';
+            var duplicates = {};
+            var length = 0;
             if (array.length > 0) {
                 output = '<table class="search-results"' + extraStyle + '>';
-                var shown = [];
 
                 array.forEach(function(item) {
-                    var name, type, href, displayPath;
-
-                    var id_ty = item.ty + item.path + item.name;
-                    if (shown.indexOf(id_ty) !== -1) {
-                        return;
-                    }
+                    var name, type;
 
-                    shown.push(id_ty);
                     name = item.name;
                     type = itemTypes[item.ty];
 
-                    var res = buildHrefAndPath(item);
-                    var href = res[1];
-                    var displayPath = res[0];
+                    if (item.is_alias !== true) {
+                        if (duplicates[item.fullPath]) {
+                            return;
+                        }
+                        duplicates[item.fullPath] = true;
+                    }
+                    length += 1;
 
                     output += '<tr class="' + type + ' result"><td>' +
-                              '<a href="' + href + '">' +
-                              pathSplitter(displayPath) + '<span class="' + type + '">' +
+                              '<a href="' + item.href + '">' +
+                              (item.is_alias === true ?
+                               ('<span class="alias"><b>' + item.alias + ' </b></span><span ' +
+                                  'class="grey"><i>&nbsp;- see&nbsp;</i></span>') : '') +
+                              item.displayPath + '<span class="' + type + '">' +
                               name + '</span></a></td><td>' +
-                              '<a href="' + href + '">' +
+                              '<a href="' + item.href + '">' +
                               '<span class="desc">' + escape(item.desc) +
                               '&nbsp;</span></a></td></tr>';
                 });
                     encodeURIComponent('rust ' + query.query) +
                     '">DuckDuckGo</a>?</div>';
             }
-            return output;
+            return [output, length];
         }
 
         function makeTabHeader(tabNb, text, nbElems) {
             if (results['others'].length === 1 &&
                 getCurrentValue('rustdoc-go-to-only-result') === "true") {
                 var elem = document.createElement('a');
-                var res = buildHrefAndPath(results['others'][0]);
-                elem.href = res[1];
+                elem.href = results['others'][0].href;
                 elem.style.display = 'none';
                 // For firefox, we need the element to be in the DOM so it can be clicked.
                 document.body.appendChild(elem);
                 elem.click();
             }
-            var output, query = getQuery(search_input.value);
+            var query = getQuery(search_input.value);
 
             currentResults = query.id;
-            output = '<h1>Results for ' + escape(query.query) +
+
+            var ret_others = addTab(results['others'], query);
+            var ret_in_args = addTab(results['in_args'], query, false);
+            var ret_returned = addTab(results['returned'], query, false);
+
+            var output = '<h1>Results for ' + escape(query.query) +
                 (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
                 '<div id="titles">' +
-                makeTabHeader(0, "In Names", results['others'].length) +
-                makeTabHeader(1, "In Parameters", results['in_args'].length) +
-                makeTabHeader(2, "In Return Types", results['returned'].length) +
-                '</div><div id="results">';
-
-            output += addTab(results['others'], query);
-            output += addTab(results['in_args'], query, false);
-            output += addTab(results['returned'], query, false);
-            output += '</div>';
+                makeTabHeader(0, "In Names", ret_others[1]) +
+                makeTabHeader(1, "In Parameters", ret_in_args[1]) +
+                makeTabHeader(2, "In Return Types", ret_returned[1]) +
+                '</div><div id="results">' +
+                ret_others[0] + ret_in_args[0] + ret_returned[0] + '</div>';
 
             addClass(document.getElementById('main'), 'hidden');
             var search = document.getElementById('search');
                 }
             }
             if (queries.length > 1) {
-                function getSmallest(arrays, positions) {
+                function getSmallest(arrays, positions, notDuplicates) {
                     var start = null;
 
                     for (var it = 0; it < positions.length; ++it) {
                         if (arrays[it].length > positions[it] &&
-                            (start === null || start > arrays[it][positions[it]].lev)) {
+                            (start === null || start > arrays[it][positions[it]].lev) &&
+                            !notDuplicates[arrays[it][positions[it]].fullPath]) {
                             start = arrays[it][positions[it]].lev;
                         }
                     }
                 function mergeArrays(arrays) {
                     var ret = [];
                     var positions = [];
+                    var notDuplicates = {};
 
                     for (var x = 0; x < arrays.length; ++x) {
                         positions.push(0);
                     }
                     while (ret.length < MAX_RESULTS) {
-                        var smallest = getSmallest(arrays, positions);
+                        var smallest = getSmallest(arrays, positions, notDuplicates);
+
                         if (smallest === null) {
                             break;
                         }
                         for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
                             if (arrays[x].length > positions[x] &&
-                                    arrays[x][positions[x]].lev === smallest) {
+                                    arrays[x][positions[x]].lev === smallest &&
+                                    !notDuplicates[arrays[x][positions[x]].fullPath]) {
                                 ret.push(arrays[x][positions[x]]);
+                                notDuplicates[arrays[x][positions[x]].fullPath] = true;
                                 positions[x] += 1;
                             }
                         }
               hasClass(next.nextElementSibling, 'docblock')))) {
             insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
         }
-    }
+    };
     onEach(document.getElementsByClassName('method'), func);
     onEach(document.getElementsByClassName('impl'), func);
     onEach(document.getElementsByClassName('impl-items'), function(e) {
index da4be7db5aa92b43088abbc4db36cba6ffc39431..493a75e25211df925b16ddbd700a3aadc3ff5e42 100644 (file)
@@ -382,7 +382,7 @@ kbd {
 }
 
 #theme-choices > button:hover, #theme-choices > button:focus {
-       background-color: #444;
+       background-color: #4e4e4e;
 }
 
 @media (max-width: 700px) {
@@ -397,3 +397,10 @@ kbd {
 #all-types:hover {
        background-color: #606060;
 }
+
+.search-results td span.alias {
+       color: #fff;
+}
+.search-results td span.grey {
+       color: #ccc;
+}
\ No newline at end of file
index 12af01d2e249809e7cde52f89116c3db8839b1fc..22f4635fb02e13ac5f23554f505503a08e46728a 100644 (file)
@@ -390,4 +390,11 @@ kbd {
 }
 #all-types:hover {
        background-color: #f9f9f9;
+}
+
+.search-results td span.alias {
+       color: #000;
+}
+.search-results td span.grey {
+       color: #999;
 }
\ No newline at end of file
index 059d41698953d2a4fcb85e36b1e45fd7e264ffa8..7d98feaf539474856e043cd263a356020abffa6d 100644 (file)
@@ -26,6 +26,8 @@
 #![feature(vec_remove_item)]
 #![feature(entry_and_modify)]
 
+#![recursion_limit="256"]
+
 extern crate arena;
 extern crate getopts;
 extern crate env_logger;
@@ -46,6 +48,7 @@
 extern crate rustc_errors as errors;
 extern crate pulldown_cmark;
 extern crate tempdir;
+extern crate minifier;
 
 extern crate serialize as rustc_serialize; // used by deriving
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::default::Default;
 use std::env;
-use std::fmt::Display;
-use std::io;
-use std::io::Write;
 use std::path::{Path, PathBuf};
 use std::process;
 use std::sync::mpsc::channel;
 
 use syntax::edition::Edition;
 use externalfiles::ExternalHtml;
+use rustc::session::{early_warn, early_error};
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
 use rustc::session::config::{nightly_options, build_codegen_options};
@@ -116,7 +117,8 @@ pub fn main() {
 fn get_args() -> Option<Vec<String>> {
     env::args_os().enumerate()
         .map(|(i, arg)| arg.into_string().map_err(|arg| {
-             print_error(format!("Argument {} is not valid Unicode: {:?}", i, arg));
+             early_warn(ErrorOutputType::default(),
+                        &format!("Argument {} is not valid Unicode: {:?}", i, arg));
         }).ok())
         .collect()
 }
@@ -297,6 +299,11 @@ pub fn opts() -> Vec<RustcOptGroup> {
                      "How errors and other messages are produced",
                      "human|json|short")
         }),
+        unstable("disable-minification", |o| {
+             o.optflag("",
+                       "disable-minification",
+                       "Disable minification applied on JS files")
+        }),
     ]
 }
 
@@ -316,16 +323,12 @@ pub fn main_args(args: &[String]) -> isize {
     let matches = match options.parse(&args[1..]) {
         Ok(m) => m,
         Err(err) => {
-            print_error(err);
-            return 1;
+            early_error(ErrorOutputType::default(), &err.to_string());
         }
     };
     // Check for unstable options.
     nightly_options::check_nightly_options(&matches, &opts());
 
-    // check for deprecated options
-    check_deprecated_options(&matches);
-
     if matches.opt_present("h") || matches.opt_present("help") {
         usage("rustdoc");
         return 0;
@@ -346,6 +349,35 @@ pub fn main_args(args: &[String]) -> isize {
         return 0;
     }
 
+    let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+        Some("auto") => ColorConfig::Auto,
+        Some("always") => ColorConfig::Always,
+        Some("never") => ColorConfig::Never,
+        None => ColorConfig::Auto,
+        Some(arg) => {
+            early_error(ErrorOutputType::default(),
+                        &format!("argument for --color must be `auto`, `always` or `never` \
+                                  (instead was `{}`)", arg));
+        }
+    };
+    let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+        Some("human") => ErrorOutputType::HumanReadable(color),
+        Some("json") => ErrorOutputType::Json(false),
+        Some("pretty-json") => ErrorOutputType::Json(true),
+        Some("short") => ErrorOutputType::Short(color),
+        None => ErrorOutputType::HumanReadable(color),
+        Some(arg) => {
+            early_error(ErrorOutputType::default(),
+                        &format!("argument for --error-format must be `human`, `json` or \
+                                  `short` (instead was `{}`)", arg));
+        }
+    };
+
+    let diag = core::new_handler(error_format, None);
+
+    // check for deprecated options
+    check_deprecated_options(&matches, &diag);
+
     let to_check = matches.opt_strs("theme-checker");
     if !to_check.is_empty() {
         let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
@@ -354,7 +386,7 @@ pub fn main_args(args: &[String]) -> isize {
         println!("rustdoc: [theme-checker] Starting tests!");
         for theme_file in to_check.iter() {
             print!(" - Checking \"{}\"...", theme_file);
-            let (success, differences) = theme::test_theme_against(theme_file, &paths);
+            let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
             if !differences.is_empty() || !success {
                 println!(" FAILED");
                 errors += 1;
@@ -372,39 +404,15 @@ pub fn main_args(args: &[String]) -> isize {
     }
 
     if matches.free.is_empty() {
-        print_error("missing file operand");
+        diag.struct_err("missing file operand").emit();
         return 1;
     }
     if matches.free.len() > 1 {
-        print_error("too many file operands");
+        diag.struct_err("too many file operands").emit();
         return 1;
     }
     let input = &matches.free[0];
 
-    let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
-        Some("auto") => ColorConfig::Auto,
-        Some("always") => ColorConfig::Always,
-        Some("never") => ColorConfig::Never,
-        None => ColorConfig::Auto,
-        Some(arg) => {
-            print_error(&format!("argument for --color must be `auto`, `always` or `never` \
-                                  (instead was `{}`)", arg));
-            return 1;
-        }
-    };
-    let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
-        Some("human") => ErrorOutputType::HumanReadable(color),
-        Some("json") => ErrorOutputType::Json(false),
-        Some("pretty-json") => ErrorOutputType::Json(true),
-        Some("short") => ErrorOutputType::Short(color),
-        None => ErrorOutputType::HumanReadable(color),
-        Some(arg) => {
-            print_error(&format!("argument for --error-format must be `human`, `json` or \
-                                  `short` (instead was `{}`)", arg));
-            return 1;
-        }
-    };
-
     let mut libs = SearchPaths::new();
     for s in &matches.opt_strs("L") {
         libs.add_path(s, error_format);
@@ -412,7 +420,7 @@ pub fn main_args(args: &[String]) -> isize {
     let externs = match parse_externs(&matches) {
         Ok(ex) => ex,
         Err(err) => {
-            print_error(err);
+            diag.struct_err(&err.to_string()).emit();
             return 1;
         }
     };
@@ -433,10 +441,7 @@ pub fn main_args(args: &[String]) -> isize {
 
     if let Some(ref p) = css_file_extension {
         if !p.is_file() {
-            writeln!(
-                &mut io::stderr(),
-                "rustdoc: option --extend-css argument must be a file."
-            ).unwrap();
+            diag.struct_err("option --extend-css argument must be a file").emit();
             return 1;
         }
     }
@@ -449,13 +454,14 @@ pub fn main_args(args: &[String]) -> isize {
                                             .iter()
                                             .map(|s| (PathBuf::from(&s), s.to_owned())) {
             if !theme_file.is_file() {
-                println!("rustdoc: option --themes arguments must all be files");
+                diag.struct_err("option --themes arguments must all be files").emit();
                 return 1;
             }
-            let (success, ret) = theme::test_theme_against(&theme_file, &paths);
+            let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
             if !success || !ret.is_empty() {
-                println!("rustdoc: invalid theme: \"{}\"", theme_s);
-                println!("         Check what's wrong with the \"theme-checker\" option");
+                diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
+                    .help("check what's wrong with the --theme-checker option")
+                    .emit();
                 return 1;
             }
             themes.push(theme_file);
@@ -467,7 +473,7 @@ pub fn main_args(args: &[String]) -> isize {
             &matches.opt_strs("html-before-content"),
             &matches.opt_strs("html-after-content"),
             &matches.opt_strs("markdown-before-content"),
-            &matches.opt_strs("markdown-after-content")) {
+            &matches.opt_strs("markdown-after-content"), &diag) {
         Some(eh) => eh,
         None => return 3,
     };
@@ -478,12 +484,13 @@ pub fn main_args(args: &[String]) -> isize {
     let linker = matches.opt_str("linker").map(PathBuf::from);
     let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
     let resource_suffix = matches.opt_str("resource-suffix");
+    let enable_minification = !matches.opt_present("disable-minification");
 
     let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
     let edition = match edition.parse() {
         Ok(e) => e,
         Err(_) => {
-            print_error("could not parse edition");
+            diag.struct_err("could not parse edition").emit();
             return 1;
         }
     };
@@ -493,7 +500,7 @@ pub fn main_args(args: &[String]) -> isize {
     match (should_test, markdown_input) {
         (true, true) => {
             return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot,
-                                  display_warnings, linker, edition, cg)
+                                  display_warnings, linker, edition, cg, &diag)
         }
         (true, false) => {
             return test::run(Path::new(input), cfgs, libs, externs, test_args, crate_name,
@@ -502,7 +509,7 @@ pub fn main_args(args: &[String]) -> isize {
         (false, true) => return markdown::render(Path::new(input),
                                                  output.unwrap_or(PathBuf::from("doc")),
                                                  &matches, &external_html,
-                                                 !matches.opt_present("markdown-no-toc")),
+                                                 !matches.opt_present("markdown-no-toc"), &diag),
         (false, false) => {}
     }
 
@@ -511,6 +518,7 @@ pub fn main_args(args: &[String]) -> isize {
     let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
                             move |out| {
         let Output { krate, passes, renderinfo } = out;
+        let diag = core::new_handler(error_format, None);
         info!("going to format");
         match output_format.as_ref().map(|s| &**s) {
             Some("html") | None => {
@@ -521,31 +529,23 @@ pub fn main_args(args: &[String]) -> isize {
                                   css_file_extension,
                                   renderinfo,
                                   sort_modules_alphabetically,
-                                  themes)
+                                  themes,
+                                  enable_minification)
                     .expect("failed to generate documentation");
                 0
             }
             Some(s) => {
-                print_error(format!("unknown output format: {}", s));
+                diag.struct_err(&format!("unknown output format: {}", s)).emit();
                 1
             }
         }
     });
     res.unwrap_or_else(|s| {
-        print_error(format!("input error: {}", s));
+        diag.struct_err(&format!("input error: {}", s)).emit();
         1
     })
 }
 
-/// Prints an uniformized error message on the standard error output
-fn print_error<T>(error_message: T) where T: Display {
-    writeln!(
-        &mut io::stderr(),
-        "rustdoc: {}\nTry 'rustdoc --help' for more information.",
-        error_message
-    ).unwrap();
-}
-
 /// Looks inside the command line arguments to extract the relevant input format
 /// and files and then generates the necessary rustdoc output for formatting.
 fn acquire_input<R, F>(input: PathBuf,
@@ -712,7 +712,7 @@ fn rust_input<R, F>(cratefile: PathBuf,
 }
 
 /// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches) {
+fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
     let deprecated_flags = [
        "input-format",
        "output-format",
@@ -724,12 +724,15 @@ fn check_deprecated_options(matches: &getopts::Matches) {
 
     for flag in deprecated_flags.into_iter() {
         if matches.opt_present(flag) {
-            eprintln!("WARNING: the '{}' flag is considered deprecated", flag);
-            eprintln!("WARNING: please see https://github.com/rust-lang/rust/issues/44136");
-        }
-    }
+            let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
+                                                    flag));
+            err.warn("please see https://github.com/rust-lang/rust/issues/44136");
 
-    if matches.opt_present("no-defaults") {
-        eprintln!("WARNING: (you may want to use --document-private-items)");
+            if *flag == "no-defaults" {
+                err.help("you may want to use --document-private-items");
+            }
+
+            err.emit();
+        }
     }
 }
index 8ada5ce1a4df9e83f74b068c903f2287038c083b..bf7b025884d5ab858628b5b18b320e7d98935f0e 100644 (file)
@@ -13,6 +13,7 @@
 use std::io::prelude::*;
 use std::path::{PathBuf, Path};
 
+use errors;
 use getopts;
 use testing;
 use rustc::session::search_paths::SearchPaths;
@@ -50,7 +51,7 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
 /// Render `input` (e.g. "foo.md") into an HTML file in `output`
 /// (e.g. output = "bar" => "bar/foo.html").
 pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
-              external_html: &ExternalHtml, include_toc: bool) -> isize {
+              external_html: &ExternalHtml, include_toc: bool, diag: &errors::Handler) -> isize {
     output.push(input.file_stem().unwrap());
     output.set_extension("html");
 
@@ -60,7 +61,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
         css.push_str(&s)
     }
 
-    let input_str = match load_string(input) {
+    let input_str = match load_string(input, diag) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
         Err(LoadStringError::BadUtf8) => return 2,
@@ -72,7 +73,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
 
     let mut out = match File::create(&output) {
         Err(e) => {
-            eprintln!("rustdoc: {}: {}", output.display(), e);
+            diag.struct_err(&format!("{}: {}", output.display(), e)).emit();
             return 4;
         }
         Ok(f) => f
@@ -80,7 +81,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
 
     let (metadata, text) = extract_leading_metadata(&input_str);
     if metadata.is_empty() {
-        eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`");
+        diag.struct_err("invalid markdown file: no initial lines starting with `# ` or `%`").emit();
         return 5;
     }
     let title = metadata[0];
@@ -130,7 +131,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
 
     match err {
         Err(e) => {
-            eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e);
+            diag.struct_err(&format!("cannot write to `{}`: {}", output.display(), e)).emit();
             6
         }
         Ok(_) => 0,
@@ -141,8 +142,8 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
 pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
             mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
             display_warnings: bool, linker: Option<PathBuf>, edition: Edition,
-            cg: CodegenOptions) -> isize {
-    let input_str = match load_string(input) {
+            cg: CodegenOptions, diag: &errors::Handler) -> isize {
+    let input_str = match load_string(input, diag) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
         Err(LoadStringError::BadUtf8) => return 2,
index 9e65fff5e2ac6f3f65c04f9a3af106a9e708c65a..fc8abafd4d89b549cb71e4b139f1a8532abec4d0 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
+use std::sync::Arc;
 
 use clean::{Crate, Item};
 use clean::cfg::Cfg;
@@ -20,7 +20,7 @@ pub fn propagate_doc_cfg(cr: Crate) -> PluginResult {
 }
 
 struct CfgPropagator {
-    parent_cfg: Option<Rc<Cfg>>,
+    parent_cfg: Option<Arc<Cfg>>,
 }
 
 impl DocFolder for CfgPropagator {
@@ -31,8 +31,8 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             (None, None) => None,
             (Some(rc), None) | (None, Some(rc)) => Some(rc),
             (Some(mut a), Some(b)) => {
-                let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
-                *Rc::make_mut(&mut a) &= b;
+                let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
+                *Arc::make_mut(&mut a) &= b;
                 Some(a)
             }
         };
index c4eaa48e49db62e47c6bb0bb3c4fc64b32f2871d..7be7ce313fcffcbc738bde5667ed6c7a1b31efdf 100644 (file)
@@ -85,77 +85,80 @@ pub fn run(input_path: &Path,
         edition,
         ..config::basic_options().clone()
     };
-
-    let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
-    let handler =
-        errors::Handler::with_tty_emitter(ColorConfig::Auto,
-                                          true, false,
-                                          Some(codemap.clone()));
-
-    let mut sess = session::build_session_(
-        sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = CStore::new(trans.metadata_loader());
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
-                                                      &sess,
-                                                      &input));
-    let driver::ExpansionResult { defs, mut hir_forest, .. } = {
-        phase_2_configure_and_expand(
-            &sess,
-            &cstore,
-            krate,
-            None,
-            "rustdoc-test",
-            None,
-            MakeGlobMap::No,
-            |_| Ok(()),
-        ).expect("phase_2_configure_and_expand aborted in rustdoc!")
-    };
-
-    let crate_name = crate_name.unwrap_or_else(|| {
-        ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
-    });
-    let mut opts = scrape_test_config(hir_forest.krate());
-    opts.display_warnings |= display_warnings;
-    let mut collector = Collector::new(crate_name,
-                                       cfgs,
-                                       libs,
-                                       cg,
-                                       externs,
-                                       false,
-                                       opts,
-                                       maybe_sysroot,
-                                       Some(codemap),
-                                       None,
-                                       linker,
-                                       edition);
-
-    {
-        let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
-        let krate = map.krate();
-        let mut hir_collector = HirCollector {
-            sess: &sess,
-            collector: &mut collector,
-            map: &map
+    driver::spawn_thread_pool(sessopts, |sessopts| {
+        let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
+        let handler =
+            errors::Handler::with_tty_emitter(ColorConfig::Auto,
+                                            true, false,
+                                            Some(codemap.clone()));
+
+        let mut sess = session::build_session_(
+            sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = CStore::new(trans.metadata_loader());
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+                                                        &sess,
+                                                        &input));
+        let driver::ExpansionResult { defs, mut hir_forest, .. } = {
+            phase_2_configure_and_expand(
+                &sess,
+                &cstore,
+                krate,
+                None,
+                "rustdoc-test",
+                None,
+                MakeGlobMap::No,
+                |_| Ok(()),
+            ).expect("phase_2_configure_and_expand aborted in rustdoc!")
         };
-        hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
-            intravisit::walk_crate(this, krate);
+
+        let crate_name = crate_name.unwrap_or_else(|| {
+            ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
         });
-    }
+        let mut opts = scrape_test_config(hir_forest.krate());
+        opts.display_warnings |= display_warnings;
+        let mut collector = Collector::new(
+            crate_name,
+            cfgs,
+            libs,
+            cg,
+            externs,
+            false,
+            opts,
+            maybe_sysroot,
+            Some(codemap),
+             None,
+            linker,
+            edition
+        );
+
+        {
+            let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
+            let krate = map.krate();
+            let mut hir_collector = HirCollector {
+                sess: &sess,
+                collector: &mut collector,
+                map: &map
+            };
+            hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
+                intravisit::walk_crate(this, krate);
+            });
+        }
 
-    test_args.insert(0, "rustdoctest".to_string());
+        test_args.insert(0, "rustdoctest".to_string());
 
-    testing::test_main(&test_args,
-                       collector.tests.into_iter().collect(),
-                       testing::Options::new().display_output(display_warnings));
-    0
+        testing::test_main(&test_args,
+                        collector.tests.into_iter().collect(),
+                        testing::Options::new().display_output(display_warnings));
+        0
+    })
 }
 
 // Look for #![doc(test(no_crate_inject))], used by crates in the std facade
@@ -229,102 +232,106 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
         ..config::basic_options().clone()
     };
 
-    // Shuffle around a few input and output handles here. We're going to pass
-    // an explicit handle into rustc to collect output messages, but we also
-    // want to catch the error message that rustc prints when it fails.
-    //
-    // We take our thread-local stderr (likely set by the test runner) and replace
-    // it with a sink that is also passed to rustc itself. When this function
-    // returns the output of the sink is copied onto the output of our own thread.
-    //
-    // The basic idea is to not use a default Handler for rustc, and then also
-    // not print things by default to the actual stderr.
-    struct Sink(Arc<Mutex<Vec<u8>>>);
-    impl Write for Sink {
-        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            Write::write(&mut *self.0.lock().unwrap(), data)
+    let (libdir, outdir) = driver::spawn_thread_pool(sessopts, |sessopts| {
+        // Shuffle around a few input and output handles here. We're going to pass
+        // an explicit handle into rustc to collect output messages, but we also
+        // want to catch the error message that rustc prints when it fails.
+        //
+        // We take our thread-local stderr (likely set by the test runner) and replace
+        // it with a sink that is also passed to rustc itself. When this function
+        // returns the output of the sink is copied onto the output of our own thread.
+        //
+        // The basic idea is to not use a default Handler for rustc, and then also
+        // not print things by default to the actual stderr.
+        struct Sink(Arc<Mutex<Vec<u8>>>);
+        impl Write for Sink {
+            fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+                Write::write(&mut *self.0.lock().unwrap(), data)
+            }
+            fn flush(&mut self) -> io::Result<()> { Ok(()) }
         }
-        fn flush(&mut self) -> io::Result<()> { Ok(()) }
-    }
-    struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
-    impl Drop for Bomb {
-        fn drop(&mut self) {
-            let _ = self.1.write_all(&self.0.lock().unwrap());
+        struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
+        impl Drop for Bomb {
+            fn drop(&mut self) {
+                let _ = self.1.write_all(&self.0.lock().unwrap());
+            }
         }
-    }
-    let data = Arc::new(Mutex::new(Vec::new()));
-    let codemap = Lrc::new(CodeMap::new_doctest(
-        sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
-    ));
-    let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
-                                                      Some(codemap.clone()),
-                                                      false,
-                                                      false);
-    let old = io::set_panic(Some(box Sink(data.clone())));
-    let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
-
-    // Compile the code
-    let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
-
-    let mut sess = session::build_session_(
-        sessopts, None, diagnostic_handler, codemap,
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = CStore::new(trans.metadata_loader());
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
-    let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
-    let mut control = driver::CompileController::basic();
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let out = Some(outdir.lock().unwrap().path().to_path_buf());
-
-    if no_run {
-        control.after_analysis.stop = Compilation::Stop;
-    }
-
-    let res = panic::catch_unwind(AssertUnwindSafe(|| {
-        driver::compile_input(
-            trans,
-            &sess,
-            &cstore,
-            &None,
-            &input,
-            &out,
-            &None,
-            None,
-            &control
-        )
-    }));
-
-    let compile_result = match res {
-        Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
-        Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
-    };
-
-    match (compile_result, compile_fail) {
-        (Ok(()), true) => {
-            panic!("test compiled while it wasn't supposed to")
+        let data = Arc::new(Mutex::new(Vec::new()));
+        let codemap = Lrc::new(CodeMap::new_doctest(
+            sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
+        ));
+        let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
+                                                        Some(codemap.clone()),
+                                                        false,
+                                                        false);
+        let old = io::set_panic(Some(box Sink(data.clone())));
+        let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
+
+        // Compile the code
+        let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
+
+        let mut sess = session::build_session_(
+            sessopts, None, diagnostic_handler, codemap,
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = CStore::new(trans.metadata_loader());
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
+        let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
+        let mut control = driver::CompileController::basic();
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let out = Some(outdir.lock().unwrap().path().to_path_buf());
+
+        if no_run {
+            control.after_analysis.stop = Compilation::Stop;
         }
-        (Ok(()), false) => {}
-        (Err(()), true) => {
-            if error_codes.len() > 0 {
-                let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
-                error_codes.retain(|err| !out.contains(err));
+
+        let res = panic::catch_unwind(AssertUnwindSafe(|| {
+            driver::compile_input(
+                trans,
+                &sess,
+                &cstore,
+                &None,
+                &input,
+                &out,
+                &None,
+                None,
+                &control
+            )
+        }));
+
+        let compile_result = match res {
+            Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
+            Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
+        };
+
+        match (compile_result, compile_fail) {
+            (Ok(()), true) => {
+                panic!("test compiled while it wasn't supposed to")
+            }
+            (Ok(()), false) => {}
+            (Err(()), true) => {
+                if error_codes.len() > 0 {
+                    let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+                    error_codes.retain(|err| !out.contains(err));
+                }
+            }
+            (Err(()), false) => {
+                panic!("couldn't compile the test")
             }
         }
-        (Err(()), false) => {
-            panic!("couldn't compile the test")
+
+        if error_codes.len() > 0 {
+            panic!("Some expected error codes were not found: {:?}", error_codes);
         }
-    }
 
-    if error_codes.len() > 0 {
-        panic!("Some expected error codes were not found: {:?}", error_codes);
-    }
+        (libdir, outdir)
+    });
 
     if no_run { return }
 
index 1e4f64f5c52c9edd51e538a637866d85a0f5879a..96a67e078875800bbc06e84183ee88a242a4b7d5 100644 (file)
 use std::io::Read;
 use std::path::Path;
 
+use errors::Handler;
+
 macro_rules! try_something {
-    ($e:expr, $out:expr) => ({
+    ($e:expr, $diag:expr, $out:expr) => ({
         match $e {
             Ok(c) => c,
             Err(e) => {
-                eprintln!("rustdoc: got an error: {}", e);
+                $diag.struct_err(&e.to_string()).emit();
                 return $out;
             }
         }
@@ -273,11 +275,13 @@ pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec<String>)
     }
 }
 
-pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath) -> (bool, Vec<String>) {
-    let mut file = try_something!(File::open(f), (false, Vec::new()));
+pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath, diag: &Handler)
+    -> (bool, Vec<String>)
+{
+    let mut file = try_something!(File::open(f), diag, (false, Vec::new()));
     let mut data = Vec::with_capacity(1000);
 
-    try_something!(file.read_to_end(&mut data), (false, Vec::new()));
+    try_something!(file.read_to_end(&mut data), diag, (false, Vec::new()));
     let paths = load_css_paths(&data);
     let mut ret = Vec::new();
     get_differences(against, &paths, &mut ret);
index 26644c769575c9bde37dd88e9af0a9077e2f54a9..7314d32b0206afaf21f55ca3a4cc925a0bf6bd2a 100644 (file)
@@ -11,9 +11,9 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f32` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
 //! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
@@ -49,6 +49,8 @@ impl f32 {
 
     /// Returns the largest integer less than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.99_f32;
     /// let g = 3.0_f32;
@@ -80,6 +82,8 @@ pub fn floor(self) -> f32 {
 
     /// Returns the smallest integer greater than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.01_f32;
     /// let g = 4.0_f32;
@@ -100,6 +104,8 @@ pub fn ceil(self) -> f32 {
     /// Returns the nearest integer to a number. Round half-way cases away from
     /// `0.0`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f32;
     /// let g = -3.3_f32;
@@ -115,6 +121,8 @@ pub fn round(self) -> f32 {
 
     /// Returns the integer part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f32;
     /// let g = -3.7_f32;
@@ -130,6 +138,8 @@ pub fn trunc(self) -> f32 {
 
     /// Returns the fractional part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -148,6 +158,8 @@ pub fn fract(self) -> f32 { self - self.trunc() }
     /// Computes the absolute value of `self`. Returns `NAN` if the
     /// number is `NAN`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -174,6 +186,8 @@ pub fn abs(self) -> f32 {
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is `NAN`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -195,8 +209,12 @@ pub fn signum(self) -> f32 {
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
+    ///
+    /// # Examples
     ///
     /// ```
     /// use std::f32;
@@ -223,6 +241,8 @@ pub fn mul_add(self, a: f32, b: f32) -> f32 {
     /// In other words, the result is `self / rhs` rounded to the integer `n`
     /// such that `self >= n * rhs`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// #![feature(euclidean_division)]
     /// let a: f32 = 7.0;
@@ -246,6 +266,8 @@ pub fn div_euc(self, rhs: f32) -> f32 {
     ///
     /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// #![feature(euclidean_division)]
     /// let a: f32 = 7.0;
@@ -271,6 +293,8 @@ pub fn mod_euc(self, rhs: f32) -> f32 {
     ///
     /// Using this function is generally faster than using `powf`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -287,6 +311,8 @@ pub fn powi(self, n: i32) -> f32 {
 
     /// Raises a number to a floating point power.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -309,6 +335,8 @@ pub fn powf(self, n: f32) -> f32 {
     ///
     /// Returns NaN if `self` is a negative number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -332,6 +360,8 @@ pub fn sqrt(self) -> f32 {
 
     /// Returns `e^(self)`, (the exponential function).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -356,6 +386,8 @@ pub fn exp(self) -> f32 {
 
     /// Returns `2^(self)`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -374,6 +406,8 @@ pub fn exp2(self) -> f32 {
 
     /// Returns the natural logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -402,6 +436,8 @@ pub fn ln(self) -> f32 {
     /// `self.log2()` can produce more accurate results for base 2, and
     /// `self.log10()` can produce more accurate results for base 10.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -418,6 +454,8 @@ pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
 
     /// Returns the base 2 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -439,6 +477,8 @@ pub fn log2(self) -> f32 {
 
     /// Returns the base 10 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -464,6 +504,8 @@ pub fn log10(self) -> f32 {
     /// * If `self <= other`: `0:0`
     /// * Else: `self - other`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -491,6 +533,8 @@ pub fn abs_sub(self, other: f32) -> f32 {
 
     /// Takes the cubic root of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -510,6 +554,8 @@ pub fn cbrt(self) -> f32 {
     /// Calculates the length of the hypotenuse of a right-angle triangle given
     /// legs of length `x` and `y`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -529,6 +575,8 @@ pub fn hypot(self, other: f32) -> f32 {
 
     /// Computes the sine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -550,6 +598,8 @@ pub fn sin(self) -> f32 {
 
     /// Computes the cosine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -571,6 +621,8 @@ pub fn cos(self) -> f32 {
 
     /// Computes the tangent of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -589,6 +641,8 @@ pub fn tan(self) -> f32 {
     /// the range [-pi/2, pi/2] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -609,6 +663,8 @@ pub fn asin(self) -> f32 {
     /// the range [0, pi] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -628,6 +684,8 @@ pub fn acos(self) -> f32 {
     /// Computes the arctangent of a number. Return value is in radians in the
     /// range [-pi/2, pi/2];
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -651,6 +709,8 @@ pub fn atan(self) -> f32 {
     /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
     /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -680,6 +740,8 @@ pub fn atan2(self, other: f32) -> f32 {
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
     /// `(sin(x), cos(x))`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -701,6 +763,8 @@ pub fn sin_cos(self) -> (f32, f32) {
     /// Returns `e^(self) - 1` in a way that is accurate even if the
     /// number is close to zero.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -720,6 +784,8 @@ pub fn exp_m1(self) -> f32 {
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
     /// the operations were performed separately.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -738,6 +804,8 @@ pub fn ln_1p(self) -> f32 {
 
     /// Hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -759,6 +827,8 @@ pub fn sinh(self) -> f32 {
 
     /// Hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -780,6 +850,8 @@ pub fn cosh(self) -> f32 {
 
     /// Hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -801,6 +873,8 @@ pub fn tanh(self) -> f32 {
 
     /// Inverse hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -823,6 +897,8 @@ pub fn asinh(self) -> f32 {
 
     /// Inverse hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -844,6 +920,8 @@ pub fn acosh(self) -> f32 {
 
     /// Inverse hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
index a7e63f59b1c67369e8bb1b1009bc950c813b95d7..75edba8979f9a1993515bf2c492381e61a5d13e5 100644 (file)
@@ -11,9 +11,9 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f64` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
 //! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
@@ -49,6 +49,8 @@ impl f64 {
 
     /// Returns the largest integer less than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.99_f64;
     /// let g = 3.0_f64;
@@ -64,6 +66,8 @@ pub fn floor(self) -> f64 {
 
     /// Returns the smallest integer greater than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.01_f64;
     /// let g = 4.0_f64;
@@ -80,6 +84,8 @@ pub fn ceil(self) -> f64 {
     /// Returns the nearest integer to a number. Round half-way cases away from
     /// `0.0`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f64;
     /// let g = -3.3_f64;
@@ -95,6 +101,8 @@ pub fn round(self) -> f64 {
 
     /// Returns the integer part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f64;
     /// let g = -3.7_f64;
@@ -110,6 +118,8 @@ pub fn trunc(self) -> f64 {
 
     /// Returns the fractional part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 3.5_f64;
     /// let y = -3.5_f64;
@@ -126,6 +136,8 @@ pub fn fract(self) -> f64 { self - self.trunc() }
     /// Computes the absolute value of `self`. Returns `NAN` if the
     /// number is `NAN`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -152,6 +164,8 @@ pub fn abs(self) -> f64 {
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is `NAN`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -173,8 +187,12 @@ pub fn signum(self) -> f64 {
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
+    ///
+    /// # Examples
     ///
     /// ```
     /// let m = 10.0_f64;
@@ -199,6 +217,8 @@ pub fn mul_add(self, a: f64, b: f64) -> f64 {
     /// In other words, the result is `self / rhs` rounded to the integer `n`
     /// such that `self >= n * rhs`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// #![feature(euclidean_division)]
     /// let a: f64 = 7.0;
@@ -222,6 +242,8 @@ pub fn div_euc(self, rhs: f64) -> f64 {
     ///
     /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// #![feature(euclidean_division)]
     /// let a: f64 = 7.0;
@@ -246,6 +268,8 @@ pub fn mod_euc(self, rhs: f64) -> f64 {
     ///
     /// Using this function is generally faster than using `powf`
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powi(2) - x*x).abs();
@@ -260,6 +284,8 @@ pub fn powi(self, n: i32) -> f64 {
 
     /// Raises a number to a floating point power.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powf(2.0) - x*x).abs();
@@ -276,6 +302,8 @@ pub fn powf(self, n: f64) -> f64 {
     ///
     /// Returns NaN if `self` is a negative number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let positive = 4.0_f64;
     /// let negative = -4.0_f64;
@@ -297,6 +325,8 @@ pub fn sqrt(self) -> f64 {
 
     /// Returns `e^(self)`, (the exponential function).
     ///
+    /// # Examples
+    ///
     /// ```
     /// let one = 1.0_f64;
     /// // e^1
@@ -315,6 +345,8 @@ pub fn exp(self) -> f64 {
 
     /// Returns `2^(self)`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 2.0_f64;
     ///
@@ -331,6 +363,8 @@ pub fn exp2(self) -> f64 {
 
     /// Returns the natural logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let one = 1.0_f64;
     /// // e^1
@@ -353,6 +387,8 @@ pub fn ln(self) -> f64 {
     /// `self.log2()` can produce more accurate results for base 2, and
     /// `self.log10()` can produce more accurate results for base 10.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let five = 5.0_f64;
     ///
@@ -367,6 +403,8 @@ pub fn log(self, base: f64) -> f64 { self.ln() / base.ln() }
 
     /// Returns the base 2 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let two = 2.0_f64;
     ///
@@ -388,6 +426,8 @@ pub fn log2(self) -> f64 {
 
     /// Returns the base 10 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let ten = 10.0_f64;
     ///
@@ -407,6 +447,8 @@ pub fn log10(self) -> f64 {
     /// * If `self <= other`: `0:0`
     /// * Else: `self - other`
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 3.0_f64;
     /// let y = -3.0_f64;
@@ -432,6 +474,8 @@ pub fn abs_sub(self, other: f64) -> f64 {
 
     /// Takes the cubic root of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 8.0_f64;
     ///
@@ -449,6 +493,8 @@ pub fn cbrt(self) -> f64 {
     /// Calculates the length of the hypotenuse of a right-angle triangle given
     /// legs of length `x` and `y`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let y = 3.0_f64;
@@ -466,6 +512,8 @@ pub fn hypot(self, other: f64) -> f64 {
 
     /// Computes the sine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -483,6 +531,8 @@ pub fn sin(self) -> f64 {
 
     /// Computes the cosine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -500,6 +550,8 @@ pub fn cos(self) -> f64 {
 
     /// Computes the tangent of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -518,6 +570,8 @@ pub fn tan(self) -> f64 {
     /// the range [-pi/2, pi/2] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -538,6 +592,8 @@ pub fn asin(self) -> f64 {
     /// the range [0, pi] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -557,6 +613,8 @@ pub fn acos(self) -> f64 {
     /// Computes the arctangent of a number. Return value is in radians in the
     /// range [-pi/2, pi/2];
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 1.0_f64;
     ///
@@ -578,6 +636,8 @@ pub fn atan(self) -> f64 {
     /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
     /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -607,6 +667,8 @@ pub fn atan2(self, other: f64) -> f64 {
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
     /// `(sin(x), cos(x))`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -628,6 +690,8 @@ pub fn sin_cos(self) -> (f64, f64) {
     /// Returns `e^(self) - 1` in a way that is accurate even if the
     /// number is close to zero.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 7.0_f64;
     ///
@@ -645,6 +709,8 @@ pub fn exp_m1(self) -> f64 {
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
     /// the operations were performed separately.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -663,6 +729,8 @@ pub fn ln_1p(self) -> f64 {
 
     /// Hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -684,6 +752,8 @@ pub fn sinh(self) -> f64 {
 
     /// Hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -705,6 +775,8 @@ pub fn cosh(self) -> f64 {
 
     /// Hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -726,6 +798,8 @@ pub fn tanh(self) -> f64 {
 
     /// Inverse hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let f = x.sinh().asinh();
@@ -746,6 +820,8 @@ pub fn asinh(self) -> f64 {
 
     /// Inverse hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let f = x.cosh().acosh();
@@ -765,6 +841,8 @@ pub fn acosh(self) -> f64 {
 
     /// Inverse hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
index 7bd1adc411ae4b1c0f19009c51f0faf1ff046643..442a0873ae075ad550e983747d6d91a06ecab75a 100644 (file)
@@ -331,6 +331,7 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
 ///
 /// fn main() -> std::io::Result<()> {
 ///     fs::write("foo.txt", b"Lorem ipsum")?;
+///     fs::write("bar.txt", "dolor sit")?;
 ///     Ok(())
 /// }
 /// ```
@@ -1699,8 +1700,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
     fs_imp::readlink(path.as_ref())
 }
 
-/// Returns the canonical form of a path with all intermediate components
-/// normalized and symbolic links resolved.
+/// Returns the canonical, absolute form of a path with all intermediate
+/// components normalized and symbolic links resolved.
 ///
 /// # Platform-specific behavior
 ///
@@ -1708,7 +1709,14 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
 /// Note that, this [may change in the future][changes].
 ///
+/// On Windows, this converts the path to use [extended length path][path]
+/// syntax, which allows your program to use longer path names, but means you
+/// can only join backslash-delimited paths to it, and it may be incompatible
+/// with other applications (if passed to the application on the command-line,
+/// or written to a file another application may read).
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
+/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
 ///
 /// # Errors
 ///
index 696711a70d4f6408cc773abf87d04ed932e64b02..86478f0a523190fc6abc64772241f2c555d7fd4a 100644 (file)
@@ -1460,7 +1460,7 @@ fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for PathBuf {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, formatter)
     }
 }
@@ -2284,8 +2284,8 @@ pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
         fs::symlink_metadata(self)
     }
 
-    /// Returns the canonical form of the path with all intermediate components
-    /// normalized and symbolic links resolved.
+    /// Returns the canonical, absolute form of the path with all intermediate
+    /// components normalized and symbolic links resolved.
     ///
     /// This is an alias to [`fs::canonicalize`].
     ///
index 437d7d74cae0d7b3f1c52dc66398e2b3290f6b62..7074928eaf6daac7dd4334b9c32803daf5c4ae46 100644 (file)
@@ -370,6 +370,8 @@ mod prim_unit { }
 //
 /// Raw, unsafe pointers, `*const T`, and `*mut T`.
 ///
+/// *[See also the `std::ptr` module](ptr/index.html).*
+///
 /// Working with raw pointers in Rust is uncommon,
 /// typically limited to a few patterns.
 ///
@@ -444,8 +446,6 @@ mod prim_unit { }
 /// but C APIs hand out a lot of pointers generally, so are a common source
 /// of raw pointers in Rust.
 ///
-/// *[See also the `std::ptr` module](ptr/index.html).*
-///
 /// [`null`]: ../std/ptr/fn.null.html
 /// [`null_mut`]: ../std/ptr/fn.null_mut.html
 /// [`is_null`]: ../std/primitive.pointer.html#method.is_null
@@ -563,6 +563,8 @@ mod prim_array { }
 //
 /// A dynamically-sized view into a contiguous sequence, `[T]`.
 ///
+/// *[See also the `std::slice` module](slice/index.html).*
+///
 /// Slices are a view into a block of memory represented as a pointer and a
 /// length.
 ///
@@ -585,8 +587,6 @@ mod prim_array { }
 /// assert_eq!(x, &[1, 7, 3]);
 /// ```
 ///
-/// *[See also the `std::slice` module](slice/index.html).*
-///
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_slice { }
 
@@ -594,15 +594,13 @@ mod prim_slice { }
 //
 /// String slices.
 ///
+/// *[See also the `std::str` module](str/index.html).*
+///
 /// The `str` type, also called a 'string slice', is the most primitive string
 /// type. It is usually seen in its borrowed form, `&str`. It is also the type
 /// of string literals, `&'static str`.
 ///
-/// Strings slices are always valid UTF-8.
-///
-/// This documentation describes a number of methods and trait implementations
-/// on the `str` type. For technical reasons, there is additional, separate
-/// documentation in the [`std::str`](str/index.html) module as well.
+/// String slices are always valid UTF-8.
 ///
 /// # Examples
 ///
@@ -862,11 +860,11 @@ mod prim_u128 { }
 //
 /// The pointer-sized signed integer type.
 ///
+/// *[See also the `std::isize` module](isize/index.html).*
+///
 /// The size of this primitive is how many bytes it takes to reference any
 /// location in memory. For example, on a 32 bit target, this is 4 bytes
 /// and on a 64 bit target, this is 8 bytes.
-///
-/// *[See also the `std::isize` module](isize/index.html).*
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_isize { }
 
@@ -874,11 +872,11 @@ mod prim_isize { }
 //
 /// The pointer-sized unsigned integer type.
 ///
+/// *[See also the `std::usize` module](usize/index.html).*
+///
 /// The size of this primitive is how many bytes it takes to reference any
 /// location in memory. For example, on a 32 bit target, this is 4 bytes
 /// and on a 64 bit target, this is 8 bytes.
-///
-/// *[See also the `std::usize` module](usize/index.html).*
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_usize { }
 
index d8d78d550162ae3ef0f6750b8b82d39b3095bec1..1ef79547431f8ac0a23d9e3a85d92c288da346fa 100644 (file)
@@ -48,13 +48,13 @@ pub fn text(&self) -> &str {
 }
 
 impl fmt::Debug for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
index 72272d0581a79d263094a03dbddce96e479622cc..4830e38d6a92fd8c4c2b337e54b97c1af0a848cc 100644 (file)
@@ -75,8 +75,15 @@ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pread64;
-            cvt(pread64(fd, buf, count, offset as i32))
+            // pread64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pread64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pread >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
@@ -116,8 +123,15 @@ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pwrite64;
-            cvt(pwrite64(fd, buf, count, offset as i32))
+            // pwrite64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pwrite64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pwrite >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
index 9e38880803026cc62abe7498c8d413997552ab2c..7fdecc9c0c026aab31787f19f6b7ed3d512706f5 100644 (file)
@@ -326,13 +326,22 @@ pub unsafe fn init() -> Option<Guard> {
             // Reallocate the last page of the stack.
             // This ensures SIGBUS will be raised on
             // stack overflow.
-            let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE,
+            // Systems which enforce strict PAX MPROTECT do not allow
+            // to mprotect() a mapping with less restrictive permissions
+            // than the initial mmap() used, so we mmap() here with
+            // read/write permissions and only then mprotect() it to
+            // no permissions at all. See issue #50313.
+            let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
-
             if result != stackaddr || result == MAP_FAILED {
                 panic!("failed to allocate a guard page");
             }
 
+            let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE);
+            if result != 0 {
+                panic!("failed to protect the guard page");
+            }
+
             let guardaddr = stackaddr as usize;
             let offset = if cfg!(target_os = "freebsd") {
                 2
index fe7e058091ed5fe1c6cf871817f879892f5ead2d..14a2555adf9baa109e7d7afe08bbea07e685826a 100644 (file)
@@ -56,7 +56,7 @@ pub struct CodePoint {
 /// Example: `U+1F4A9`
 impl fmt::Debug for CodePoint {
     #[inline]
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(formatter, "U+{:04X}", self.value)
     }
 }
@@ -144,7 +144,7 @@ fn deref_mut(&mut self) -> &mut Wtf8 {
 /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
 impl fmt::Debug for Wtf8Buf {
     #[inline]
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, formatter)
     }
 }
index ace9904e0c021e57b39ff6005883d6afbaa80d19..fcda6ce9b164deb00384bcba5b31aba3bc6332db 100644 (file)
@@ -1348,7 +1348,7 @@ fn from_token(token: Token) -> Option<LitKind> {
             Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)),
             Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)),
             Token::Interpolated(ref nt) => match nt.0 {
-                token::NtExpr(ref v) => match v.node {
+                token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
                     ExprKind::Lit(ref lit) => Some(lit.node.clone()),
                     _ => None,
                 },
index 7341941c242a4a743092b4f125f6a4cf03fd87a9..c98b54581f35f4bde3d13bddad600106f419611c 100644 (file)
@@ -50,8 +50,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl Edition {
     pub fn lint_name(&self) -> &'static str {
         match *self {
-            Edition::Edition2015 => "rust_2015_breakage",
-            Edition::Edition2018 => "rust_2018_breakage",
+            Edition::Edition2015 => "rust_2015_compatibility",
+            Edition::Edition2018 => "rust_2018_compatibility",
         }
     }
 
index eeed291c0caaf0d3404d27595668bc9caf733930..a6e6ccde72c9f46b2b0a54b0fbf82d7c9497a9e8 100644 (file)
@@ -711,6 +711,7 @@ macro_rules! mk_lit {
         token::Pound        => "Pound",
         token::Dollar       => "Dollar",
         token::Question     => "Question",
+        token::SingleQuote  => "SingleQuote",
         token::Eof          => "Eof",
 
         token::Whitespace | token::Comment | token::Shebang(_) => {
index 71634ada89458012b70f6b307c5f7dca3bf33ddc..f0339b89839c1609dc853f5bf63c1eb7693f658c 100644 (file)
@@ -735,6 +735,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         "expr" => token.can_begin_expr(),
         "ty" => token.can_begin_type(),
         "ident" => get_macro_ident(token).is_some(),
+        "literal" => token.can_begin_literal_or_bool(),
         "vis" => match *token {
             // The follow-set of :vis + "priv" keyword + interpolated
             Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true,
@@ -821,6 +822,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         },
         "pat" => token::NtPat(panictry!(p.parse_pat())),
         "expr" => token::NtExpr(panictry!(p.parse_expr())),
+        "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
         "ty" => token::NtTy(panictry!(p.parse_ty())),
         // this could be handled like a token, since it is one
         "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) {
index ffe68289d5224be79aa5cb086791919d07b08abc..e96a0e838cfcd50a46429727a3b3180294d1e039 100644 (file)
@@ -647,7 +647,7 @@ fn check_matcher_core(sess: &ParseSess,
                     let msg = format!("invalid fragment specifier `{}`", bad_frag);
                     sess.span_diagnostic.struct_span_err(token.span(), &msg)
                         .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
-                              `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`")
+                              `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`")
                         .emit();
                     // (This eliminates false positives and duplicates
                     // from error messages.)
@@ -784,6 +784,7 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
         "item"     | // always terminated by `}` or `;`
         "block"    | // exactly one token tree
         "ident"    | // exactly one token tree
+        "literal"  | // exactly one token tree
         "meta"     | // exactly one token tree
         "lifetime" | // exactly one token tree
         "tt" =>   // exactly one token tree
@@ -850,6 +851,10 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
                 // being a single token, idents and lifetimes are harmless
                 Ok(true)
             },
+            "literal" => {
+                // literals may be of a single token, or two tokens (negative numbers)
+                Ok(true)
+            },
             "meta" | "tt" => {
                 // being either a single token or a delimited sequence, tt is
                 // harmless
@@ -873,7 +878,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
             _ => Err((format!("invalid fragment specifier `{}`", frag),
                      "valid fragment specifiers are `ident`, `block`, \
                       `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
-                      `item` and `vis`"))
+                      `literal`, `item` and `vis`"))
         }
     }
 }
@@ -899,14 +904,14 @@ fn is_legal_fragment_specifier(sess: &ParseSess,
                                frag_name: &str,
                                frag_span: Span) -> bool {
     match frag_name {
-        "item" | "block" | "stmt" | "expr" | "pat" |
+        "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" |
         "path" | "ty" | "ident" | "meta" | "tt" | "" => true,
-        "lifetime" => {
-            if !features.macro_lifetime_matcher &&
+        "literal" => {
+            if !features.macro_literal_matcher &&
                !attr::contains_name(attrs, "allow_internal_unstable") {
-                let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER;
+                let explain = feature_gate::EXPLAIN_LITERAL_MATCHER;
                 emit_feature_err(sess,
-                                 "macro_lifetime_matcher",
+                                 "macro_literal_matcher",
                                  frag_span,
                                  GateIssue::Language,
                                  explain);
index 5155408ba63f3143372f4a1db5ea19b312dca792..bf78723e41365f8f5e961e59015a9214c042af88 100644 (file)
@@ -190,7 +190,7 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     (active, rustc_attrs, "1.0.0", Some(29642), None),
 
     // Allows the use of non lexical lifetimes; RFC 2094
-    (active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
+    (active, nll, "1.0.0", Some(43234), None),
 
     // Allows the use of #[allow_internal_unstable]. This is an
     // attribute on macro_rules! and can't use the attribute handling
@@ -396,9 +396,6 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // Termination trait in tests (RFC 1937)
     (active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
 
-    // Allows use of the :lifetime macro fragment specifier
-    (active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
-
     // `extern` in paths
     (active, extern_in_paths, "1.23.0", Some(44660), None),
 
@@ -463,6 +460,12 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
 
     // Scoped attributes
     (active, tool_attributes, "1.25.0", Some(44690), None),
+
+    // Allows use of the :literal macro fragment specifier (RFC 1576)
+    (active, macro_literal_matcher, "1.27.0", Some(35625), None),
+
+    // inconsistent bounds in where clauses
+    (active, trivial_bounds, "1.28.0", Some(48214), None),
 );
 
 declare_features! (
@@ -595,6 +598,8 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     (accepted, dyn_trait, "1.27.0", Some(44662), None),
     // allow `#[must_use]` on functions; and, must-use operators (RFC 1940)
     (accepted, fn_must_use, "1.27.0", Some(43302), None),
+    // Allows use of the :lifetime macro fragment specifier
+    (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -1328,8 +1333,8 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue
 pub const EXPLAIN_VIS_MATCHER: &'static str =
     ":vis fragment specifier is experimental and subject to change";
 
-pub const EXPLAIN_LIFETIME_MATCHER: &'static str =
-    ":lifetime fragment specifier is experimental and subject to change";
+pub const EXPLAIN_LITERAL_MATCHER: &'static str =
+    ":literal fragment specifier is experimental and subject to change";
 
 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
     "Unsized tuple coercion is not stable enough for use and is subject to change";
@@ -1861,56 +1866,61 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
             continue
         }
 
-        match attr.meta_item_list() {
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
             None => {
                 span_err!(span_handler, attr.span, E0555,
                           "malformed feature attribute, expected #![feature(...)]");
+                continue
+            }
+        };
+
+        for mi in list {
+            let name = if let Some(word) = mi.word() {
+                word.name()
+            } else {
+                span_err!(span_handler, mi.span, E0556,
+                          "malformed feature, expected just one word");
+                continue
+            };
+
+            if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
+                set(&mut features, mi.span);
+                feature_checker.collect(&features, mi.span);
+                continue
             }
-            Some(list) => {
-                for mi in list {
 
-                    let name = if let Some(word) = mi.word() {
-                        word.name()
-                    } else {
-                        span_err!(span_handler, mi.span, E0556,
-                                  "malformed feature, expected just one word");
-                        continue
-                    };
-
-                    if let Some(&(_, _, _, _, set)) = ACTIVE_FEATURES.iter()
-                        .find(|& &(n, ..)| name == n) {
-                        set(&mut features, mi.span);
-                        feature_checker.collect(&features, mi.span);
-                    }
-                    else if let Some(&(.., reason)) = REMOVED_FEATURES.iter()
-                            .find(|& &(n, ..)| name == n)
-                        .or_else(|| STABLE_REMOVED_FEATURES.iter()
-                            .find(|& &(n, ..)| name == n)) {
-                        feature_removed(span_handler, mi.span, reason);
-                    }
-                    else if let Some(&(..)) = ACCEPTED_FEATURES.iter()
-                        .find(|& &(n, ..)| name == n) {
-                        features.declared_stable_lang_features.push((name, mi.span));
-                    } else if let Some(&edition) = ALL_EDITIONS.iter()
-                                                              .find(|e| name == e.feature_name()) {
-                        if edition <= crate_edition {
-                            feature_removed(span_handler, mi.span, None);
-                        } else {
-                            for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
-                                if let Some(f_edition) = f_edition {
-                                    if edition >= f_edition {
-                                        // FIXME(Manishearth) there is currently no way to set
-                                        // lib features by edition
-                                        set(&mut features, DUMMY_SP);
-                                    }
-                                }
-                            }
+            let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
+            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
+            if let Some((.., reason)) = removed.or(stable_removed) {
+                feature_removed(span_handler, mi.span, *reason);
+                continue
+            }
+
+            if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
+                features.declared_stable_lang_features.push((name, mi.span));
+                continue
+            }
+
+            if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
+                if *edition <= crate_edition {
+                    continue
+                }
+
+                for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+                    if let Some(f_edition) = f_edition {
+                        if *edition >= f_edition {
+                            // FIXME(Manishearth) there is currently no way to set
+                            // lib features by edition
+                            set(&mut features, DUMMY_SP);
                         }
-                    } else {
-                        features.declared_lib_features.push((name, mi.span));
                     }
                 }
+
+                continue
             }
+
+            features.declared_lib_features.push((name, mi.span));
         }
     }
 
index a0cd831a9ba080cb5ae532fa869c0ec9e0739036..d67995761f6271c2c04e79dc7dd0b64a10fad732 100644 (file)
@@ -635,6 +635,7 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
         token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
         token::NtIdent(ident, is_raw) => token::NtIdent(fld.fold_ident(ident), is_raw),
         token::NtLifetime(ident) => token::NtLifetime(fld.fold_ident(ident)),
+        token::NtLiteral(expr) => token::NtLiteral(fld.fold_expr(expr)),
         token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)),
         token::NtPath(path) => token::NtPath(fld.fold_path(path)),
         token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)),
index f148aaf7267eec9dc581fdfc025d8f2884df44b6..90af3ba51ecadcff1a3d7fdf58c90099df2c14b4 100644 (file)
@@ -73,7 +73,7 @@ macro_rules! unwrap_or {
     }
 }
 
-struct Globals {
+pub struct Globals {
     used_attrs: Lock<Vec<u64>>,
     known_attrs: Lock<Vec<u64>>,
     syntax_pos_globals: syntax_pos::Globals,
@@ -98,7 +98,7 @@ pub fn with_globals<F, R>(f: F) -> R
     })
 }
 
-scoped_thread_local!(static GLOBALS: Globals);
+scoped_thread_local!(pub static GLOBALS: Globals);
 
 #[macro_use]
 pub mod diagnostics {
index 22a0261d8c6b15fe9c05b4ce9e2634aa6f69d9b4..3e22598043a3ed1cfef9adf8c5d17626ef778357 100644 (file)
@@ -1770,6 +1770,12 @@ fn ident_continue(c: Option<char>) -> bool {
     (c > '\x7f' && c.is_xid_continue())
 }
 
+// The string is a valid identifier or a lifetime identifier.
+pub fn is_valid_ident(s: &str) -> bool {
+    let mut chars = s.chars();
+    ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch)))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index bf4a68679df55aacb3637bcaf8b7c5cab1bb5882..3f0df6d055b76b656ea100521220fe7cd8b09de3 100644 (file)
@@ -115,7 +115,7 @@ macro_rules! maybe_whole_expr {
     ($p:expr) => {
         if let token::Interpolated(nt) = $p.token.clone() {
             match nt.0 {
-                token::NtExpr(ref e) => {
+                token::NtExpr(ref e) | token::NtLiteral(ref e) => {
                     $p.bump();
                     return Ok((*e).clone());
                 }
@@ -1823,7 +1823,7 @@ pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::E
     pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> {
         let out = match self.token {
             token::Interpolated(ref nt) => match nt.0 {
-                token::NtExpr(ref v) => match v.node {
+                token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
                     ExprKind::Lit(ref lit) => { lit.node.clone() }
                     _ => { return self.unexpected_last(&self.token); }
                 },
@@ -1862,7 +1862,7 @@ pub fn parse_lit(&mut self) -> PResult<'a, Lit> {
     }
 
     /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat)
-    pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
+    pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
         maybe_whole_expr!(self);
 
         let minus_lo = self.span;
@@ -2407,10 +2407,10 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     hi = pth.span;
                     ex = ExprKind::Path(None, pth);
                 } else {
-                    match self.parse_lit() {
-                        Ok(lit) => {
-                            hi = lit.span;
-                            ex = ExprKind::Lit(P(lit));
+                    match self.parse_literal_maybe_minus() {
+                        Ok(expr) => {
+                            hi = expr.span;
+                            ex = expr.node.clone();
                         }
                         Err(mut err) => {
                             self.cancel(&mut err);
@@ -3724,7 +3724,7 @@ fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
             let hi = self.prev_span;
             Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
         } else {
-            self.parse_pat_literal_maybe_minus()
+            self.parse_literal_maybe_minus()
         }
     }
 
@@ -3914,7 +3914,7 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
                 }
             } else {
                 // Try to parse everything else as literal with optional minus
-                match self.parse_pat_literal_maybe_minus() {
+                match self.parse_literal_maybe_minus() {
                     Ok(begin) => {
                         if self.eat(&token::DotDotDot) {
                             let end = self.parse_pat_range_end()?;
@@ -5741,7 +5741,7 @@ pub fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
                 let vis = p.parse_visibility(true)?;
                 let ty = p.parse_ty()?;
                 Ok(StructField {
-                    span: lo.to(p.span),
+                    span: lo.to(ty.span),
                     vis,
                     ident: None,
                     id: ast::DUMMY_NODE_ID,
index 938711ca1d495f02cd68e3110956db99a9390ed9..a1c056cbb2ccbbb368627aedf17af5dff840ad16 100644 (file)
@@ -210,6 +210,8 @@ pub enum Token {
     Pound,
     Dollar,
     Question,
+    /// Used by proc macros for representing lifetimes, not generated by lexer right now.
+    SingleQuote,
     /// An opening delimiter, eg. `{`
     OpenDelim(DelimToken),
     /// A closing delimiter, eg. `}`
@@ -280,7 +282,12 @@ pub fn can_begin_expr(&self) -> bool {
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
             Interpolated(ref nt) => match nt.0 {
-                NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true,
+                NtLiteral(..) |
+                NtIdent(..)   |
+                NtExpr(..)    |
+                NtBlock(..)   |
+                NtPath(..)    |
+                NtLifetime(..) => true,
                 _ => false,
             },
             _ => false,
@@ -324,6 +331,18 @@ pub fn is_lit(&self) -> bool {
         }
     }
 
+    /// Returns `true` if the token is any literal, a minus (which can follow a literal,
+    /// for example a '-42', or one of the boolean idents).
+    pub fn can_begin_literal_or_bool(&self) -> bool {
+        match *self {
+            Literal(..)  => true,
+            BinOp(Minus) => true,
+            Ident(ident, false) if ident.name == keywords::True.name() => true,
+            Ident(ident, false) if ident.name == keywords::False.name() => true,
+            _            => false,
+        }
+    }
+
     /// Returns an identifier if this token is an identifier.
     pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
         match *self {
@@ -496,6 +515,10 @@ pub fn glue(self, joint: Token) -> Option<Token> {
                 Colon => ModSep,
                 _ => return None,
             },
+            SingleQuote => match joint {
+                Ident(ident, false) => Lifetime(ident),
+                _ => return None,
+            },
 
             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
             DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
@@ -672,6 +695,7 @@ pub enum Nonterminal {
     NtTy(P<ast::Ty>),
     NtIdent(ast::Ident, /* is_raw */ bool),
     NtLifetime(ast::Ident),
+    NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
     NtMeta(ast::MetaItem),
     NtPath(ast::Path),
@@ -713,6 +737,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             NtExpr(..) => f.pad("NtExpr(..)"),
             NtTy(..) => f.pad("NtTy(..)"),
             NtIdent(..) => f.pad("NtIdent(..)"),
+            NtLiteral(..) => f.pad("NtLiteral(..)"),
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
             NtTT(..) => f.pad("NtTT(..)"),
index b8ddb063d98751fc94cead427f1527712adace3c..8e33fa08083967689644a66c597c54ff761098ef 100644 (file)
@@ -224,6 +224,7 @@ pub fn token_to_string(tok: &Token) -> String {
         token::Pound                => "#".to_string(),
         token::Dollar               => "$".to_string(),
         token::Question             => "?".to_string(),
+        token::SingleQuote          => "'".to_string(),
 
         /* Literals */
         token::Literal(lit, suf) => {
@@ -273,6 +274,7 @@ pub fn token_to_string(tok: &Token) -> String {
             token::NtIdent(e, false)    => ident_to_string(e),
             token::NtIdent(e, true)     => format!("r#{}", ident_to_string(e)),
             token::NtLifetime(e)        => ident_to_string(e),
+            token::NtLiteral(ref e)     => expr_to_string(e),
             token::NtTT(ref tree)       => tt_to_string(tree.clone()),
             token::NtArm(ref e)         => arm_to_string(e),
             token::NtImplItem(ref e)    => impl_item_to_string(e),
index d71527fd0ed0f960f11502401150d58b1575a74a..2b3930063f369028e9c23122ff398e1885d61c0a 100644 (file)
@@ -147,34 +147,37 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
             // as the outermost one, and the last as the innermost.
             false,
             |cx, span, old, self_f, other_fs| {
-        // match new {
-        //     Some(::std::cmp::Ordering::Equal) => old,
-        //     cmp => cmp
-        // }
+                // match new {
+                //     Some(::std::cmp::Ordering::Equal) => old,
+                //     cmp => cmp
+                // }
 
-        let new = {
-            let other_f = match (other_fs.len(), other_fs.get(0)) {
-                (1, Some(o_f)) => o_f,
-                _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
-            };
+                let new = {
+                    let other_f = match (other_fs.len(), other_fs.get(0)) {
+                        (1, Some(o_f)) => o_f,
+                                _ => {
+                                    cx.span_bug(span,
+                                        "not exactly 2 arguments in `derive(PartialOrd)`")
+                                }
+                    };
 
-            let args = vec![
-                    cx.expr_addr_of(span, self_f),
-                    cx.expr_addr_of(span, other_f.clone()),
-                ];
+                    let args = vec![
+                            cx.expr_addr_of(span, self_f),
+                            cx.expr_addr_of(span, other_f.clone()),
+                        ];
 
-            cx.expr_call_global(span, partial_cmp_path.clone(), args)
-        };
+                    cx.expr_call_global(span, partial_cmp_path.clone(), args)
+                };
 
-        let eq_arm = cx.arm(span,
-                            vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
-                            old);
-        let neq_arm = cx.arm(span,
-                             vec![cx.pat_ident(span, test_id)],
-                             cx.expr_ident(span, test_id));
+                let eq_arm = cx.arm(span,
+                                    vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
+                                    old);
+                let neq_arm = cx.arm(span,
+                                    vec![cx.pat_ident(span, test_id)],
+                                    cx.expr_ident(span, test_id));
 
-        cx.expr_match(span, new, vec![eq_arm, neq_arm])
-    },
+                cx.expr_match(span, new, vec![eq_arm, neq_arm])
+            },
             equals_expr.clone(),
             Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
         if self_args.len() != 2 {
@@ -189,78 +192,99 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
 }
 
 /// Strict inequality.
-fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
-    let strict_op = if less { BinOpKind::Lt } else { BinOpKind::Gt };
-    cs_fold1(false, // need foldr,
+fn cs_op(less: bool,
+         inclusive: bool,
+         cx: &mut ExtCtxt,
+         span: Span,
+         substr: &Substructure) -> P<Expr> {
+    let ordering_path = |cx: &mut ExtCtxt, name: &str| {
+        cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", "Ordering", name])))
+    };
+
+    let par_cmp = |cx: &mut ExtCtxt, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
+        let other_f = match (other_fs.len(), other_fs.get(0)) {
+            (1, Some(o_f)) => o_f,
+            _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
+        };
+
+        // `PartialOrd::partial_cmp(self.fi, other.fi)`
+        let cmp_path = cx.expr_path(cx.path_global(span, cx.std_path(&["cmp",
+                                                                       "PartialOrd",
+                                                                       "partial_cmp"])));
+        let cmp = cx.expr_call(span,
+                               cmp_path,
+                               vec![cx.expr_addr_of(span, self_f),
+                                    cx.expr_addr_of(span, other_f.clone())]);
+
+        let default = ordering_path(cx, default);
+        // `Option::unwrap_or(_, Ordering::Equal)`
+        let unwrap_path = cx.expr_path(cx.path_global(span, cx.std_path(&["option",
+                                                                          "Option",
+                                                                          "unwrap_or"])));
+        cx.expr_call(span, unwrap_path, vec![cmp, default])
+    };
+
+    let fold = cs_fold1(false, // need foldr
         |cx, span, subexpr, self_f, other_fs| {
-            // build up a series of chain ||'s and &&'s from the inside
+            // build up a series of `partial_cmp`s from the inside
             // out (hence foldr) to get lexical ordering, i.e. for op ==
             // `ast::lt`
             //
             // ```
-            // self.f1 < other.f1 || (!(other.f1 < self.f1) &&
-            // self.f2 < other.f2
+            // Ordering::then_with(
+            //    Option::unwrap_or(
+            //        PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
+            //    ),
+            //    Option::unwrap_or(
+            //        PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
+            //    )
             // )
+            // == Ordering::Less
             // ```
             //
             // and for op ==
             // `ast::le`
             //
             // ```
-            // self.f1 < other.f1 || (self.f1 == other.f1 &&
-            // self.f2 <= other.f2
+            // Ordering::then_with(
+            //    Option::unwrap_or(
+            //        PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
+            //    ),
+            //    Option::unwrap_or(
+            //        PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
+            //    )
             // )
+            // != Ordering::Greater
             // ```
             //
             // The optimiser should remove the redundancy. We explicitly
             // get use the binops to avoid auto-deref dereferencing too many
             // layers of pointers, if the type includes pointers.
-            //
-            let other_f = match (other_fs.len(), other_fs.get(0)) {
-                (1, Some(o_f)) => o_f,
-                _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
-            };
 
-            let strict_ineq = cx.expr_binary(span, strict_op, self_f.clone(), other_f.clone());
+            // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)`
+            let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal");
 
-            let deleg_cmp = if !equal {
-                cx.expr_unary(span,
-                            ast::UnOp::Not,
-                            cx.expr_binary(span, strict_op, other_f.clone(), self_f))
-            } else {
-                cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone())
-            };
-
-            let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr);
-            cx.expr_binary(span, BinOpKind::Or, strict_ineq, and)
+            // `Ordering::then_with(Option::unwrap_or(..), ..)`
+            let then_with_path = cx.expr_path(cx.path_global(span,
+                                                             cx.std_path(&["cmp",
+                                                                           "Ordering",
+                                                                           "then_with"])));
+            cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)])
         },
         |cx, args| {
             match args {
                 Some((span, self_f, other_fs)) => {
-                    // Special-case the base case to generate cleaner code with
-                    // fewer operations (e.g. `<=` instead of `<` and `==`).
-                    let other_f = match (other_fs.len(), other_fs.get(0)) {
-                        (1, Some(o_f)) => o_f,
-                        _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
-                    };
-
-                    let op = match (less, equal) {
-                        (false, false) => BinOpKind::Gt,
-                        (false, true) => BinOpKind::Ge,
-                        (true, false) => BinOpKind::Lt,
-                        (true, true) => BinOpKind::Le,
-                    };
-
-                    cx.expr_binary(span, op, self_f, other_f.clone())
-                }
-                None => cx.expr_bool(span, equal)
+                    let opposite = if less { "Greater" } else { "Less" };
+                    par_cmp(cx, span, self_f, other_fs, opposite)
+                },
+                None => cx.expr_bool(span, inclusive)
             }
         },
         Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
             if self_args.len() != 2 {
                 cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
             } else {
-                let op = match (less, equal) {
+                let op = match (less, inclusive) {
                     (false, false) => GtOp,
                     (false, true) => GeOp,
                     (true, false) => LtOp,
@@ -271,5 +295,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru
         }),
         cx,
         span,
-        substr)
+        substr);
+
+    match *substr.fields {
+        EnumMatching(.., ref all_fields) |
+        Struct(.., ref all_fields) if !all_fields.is_empty() => {
+            let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" });
+            let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq };
+
+            cx.expr_binary(span, comp_op, fold, ordering)
+        }
+        _ => fold
+    }
 }
index e95c6f2e1243fe7f5a2556d64d243eb3c30e12b4..2b8603c75a57b50733b0ac0ec611b8fd438b93d4 100644 (file)
@@ -989,7 +989,7 @@ fn clone(&self) -> StrCursor<'a> {
     }
 
     impl<'a> std::fmt::Debug for StrCursor<'a> {
-        fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+        fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
             write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
         }
     }
index b9637b1855ef08760a3ed96b6afdedd1aae4ecb5..a9147b394f7a498406baec5c22449ed2943c1c16 100644 (file)
@@ -11,5 +11,6 @@ crate-type = ["dylib"]
 [dependencies]
 serialize = { path = "../libserialize" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+arena = { path = "../libarena" }
 scoped-tls = { version = "0.1.1", features = ["nightly"] }
 unicode-width = "0.1.4"
index 658408519b9c7ead442eb045feb90ac82e258f1a..be031ea98c9d2ecb4b8deabc1dca001ebca1a5d1 100644 (file)
@@ -13,7 +13,7 @@
 //! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
 //! *Macros that work together: Compile-time bindings, partial expansion,
 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
-//! DOI=10.1017/S0956796812000093 <http://dx.doi.org/10.1017/S0956796812000093>
+//! DOI=10.1017/S0956796812000093 <https://doi.org/10.1017/S0956796812000093>
 
 use GLOBALS;
 use Span;
index 8b4a3ea26a1ef7dca52f5a179e2f0110c7ea5f3f..d30d3d78ca5404dbea9f10b29f81f272b6c5af35 100644 (file)
@@ -35,6 +35,7 @@
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{Lrc, Lock};
 
+extern crate arena;
 extern crate rustc_data_structures;
 
 #[macro_use]
index b55fe4bcb26721ad8f913adbb441a9ade7294cc1..601a0273ae91178efa1b52a9c58321a1ea397d7c 100644 (file)
 
 impl Copy for Span {}
 impl Clone for Span {
+    #[inline]
     fn clone(&self) -> Span {
         *self
     }
 }
 impl PartialEq for Span {
+    #[inline]
     fn eq(&self, other: &Span) -> bool {
         let a = self.0;
         let b = other.0;
@@ -44,6 +46,7 @@ fn eq(&self, other: &Span) -> bool {
 }
 impl Eq for Span {}
 impl Hash for Span {
+    #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         let a = self.0;
         a.hash(state)
index 4a8b1e8b1c1e46edb8569c04006a1258a9be7b0a..2258ed12779e4ce7792a195d9cfaa234db812bac 100644 (file)
 use {Span, DUMMY_SP, GLOBALS};
 
 use rustc_data_structures::fx::FxHashMap;
+use arena::DroplessArena;
 use serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
+use std::str;
 use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
 use std::hash::{Hash, Hasher};
 
@@ -198,22 +200,35 @@ fn eq(&self, other: &T) -> bool {
     }
 }
 
-#[derive(Default)]
+// The &'static strs in this type actually point into the arena
 pub struct Interner {
-    names: FxHashMap<Box<str>, Symbol>,
-    strings: Vec<Box<str>>,
+    arena: DroplessArena,
+    names: FxHashMap<&'static str, Symbol>,
+    strings: Vec<&'static str>,
     gensyms: Vec<Symbol>,
 }
 
 impl Interner {
     pub fn new() -> Self {
-        Interner::default()
+        Interner {
+            arena: DroplessArena::new(),
+            names: Default::default(),
+            strings: Default::default(),
+            gensyms: Default::default(),
+        }
     }
 
     fn prefill(init: &[&str]) -> Self {
         let mut this = Interner::new();
         for &string in init {
-            this.intern(string);
+            if string == "" {
+                // We can't allocate empty strings in the arena, so handle this here
+                let name = Symbol(this.strings.len() as u32);
+                this.names.insert("", name);
+                this.strings.push("");
+            } else {
+                this.intern(string);
+            }
         }
         this
     }
@@ -224,8 +239,17 @@ pub fn intern(&mut self, string: &str) -> Symbol {
         }
 
         let name = Symbol(self.strings.len() as u32);
-        let string = string.to_string().into_boxed_str();
-        self.strings.push(string.clone());
+
+        // from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
+        let string: &str = unsafe {
+            str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
+        };
+        // It is safe to extend the arena allocation to 'static because we only access
+        // these while the arena is still alive
+        let string: &'static str =  unsafe {
+            &*(string as *const str)
+        };
+        self.strings.push(string);
         self.names.insert(string, name);
         name
     }
@@ -254,7 +278,7 @@ fn is_gensymed(&mut self, symbol: Symbol) -> bool {
 
     pub fn get(&self, symbol: Symbol) -> &str {
         match self.strings.get(symbol.0 as usize) {
-            Some(ref string) => string,
+            Some(string) => string,
             None => self.get(self.gensyms[(!0 - symbol.0) as usize]),
         }
     }
@@ -503,7 +527,7 @@ fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
         if self.symbol == other.symbol {
             return Some(Ordering::Equal);
         }
-        self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str)))
+        self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
     }
 }
 
index b6c1a03fb498f6c03d1cbfd4404223a046f8c3b2..fd7dd99edf371ac502ae4e70288c027f6692ace0 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit b6c1a03fb498f6c03d1cbfd4404223a046f8c3b2
+Subproject commit fd7dd99edf371ac502ae4e70288c027f6692ace0
index 382ef2cc407dd93ba704457c5fee7a58073fde86..8593f543619a59ba5aa1b4e0db00bfaa9e20e3b2 100644 (file)
@@ -428,13 +428,16 @@ extern "C" void LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
 
 extern "C" void LLVMRustConfigurePassManagerBuilder(
     LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
-    bool MergeFunctions, bool SLPVectorize, bool LoopVectorize,
+    bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
     const char* PGOGenPath, const char* PGOUsePath) {
   // Ignore mergefunc for now as enabling it causes crashes.
   // unwrap(PMBR)->MergeFunctions = MergeFunctions;
   unwrap(PMBR)->SLPVectorize = SLPVectorize;
   unwrap(PMBR)->OptLevel = fromRust(OptLevel);
   unwrap(PMBR)->LoopVectorize = LoopVectorize;
+#if LLVM_VERSION_GE(4, 0)
+  unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+#endif
 
 #ifdef PGO_AVAILABLE
   if (PGOGenPath) {
index 2f86c75a2479cf051b92fc98273daaf7f151e7a1..a19ca1cd91cf97777af8268a6136bd2e4648e189 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1
+Subproject commit a19ca1cd91cf97777af8268a6136bd2e4648e189
index 415ee6eb7eab8754834de460088b0ac260935313..1879002e7f3d7cb2750ca73b9aad7aedda4a8347 100644 (file)
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = constant i32 1, section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
-#[cfg(target_endian = "little")]
 pub static VAR1: u32 = 1;
 
-#[no_mangle]
-#[link_section = ".test_one"]
-#[cfg(target_endian = "big")]
-pub static VAR1: u32 = 0x01000000;
-
 pub enum E {
     A(u32),
     B(f32)
index 6b34ccc6543ea230ff9072e80e89d19f0ae52989..f3f7cb1406cbd26359449f582cc13f78040d4492 100644 (file)
@@ -53,7 +53,7 @@ pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream {
 
 fn assert_inline(slice: &mut &[TokenTree]) {
     match &slice[0] {
-        TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
+        TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
         _ => panic!("expected '#' char"),
     }
     match &slice[1] {
@@ -65,8 +65,8 @@ fn assert_inline(slice: &mut &[TokenTree]) {
 
 fn assert_doc(slice: &mut &[TokenTree]) {
     match &slice[0] {
-        TokenTree::Op(tt) => {
-            assert_eq!(tt.op(), '#');
+        TokenTree::Punct(tt) => {
+            assert_eq!(tt.as_char(), '#');
             assert_eq!(tt.spacing(), Spacing::Alone);
         }
         _ => panic!("expected #"),
@@ -86,12 +86,12 @@ fn assert_doc(slice: &mut &[TokenTree]) {
     }
 
     match &tokens[0] {
-        TokenTree::Term(tt) => assert_eq!("doc", &*tt.to_string()),
+        TokenTree::Ident(tt) => assert_eq!("doc", &*tt.to_string()),
         _ => panic!("expected `doc`"),
     }
     match &tokens[1] {
-        TokenTree::Op(tt) => {
-            assert_eq!(tt.op(), '=');
+        TokenTree::Punct(tt) => {
+            assert_eq!(tt.as_char(), '=');
             assert_eq!(tt.spacing(), Spacing::Alone);
         }
         _ => panic!("expected equals"),
@@ -106,7 +106,7 @@ fn assert_doc(slice: &mut &[TokenTree]) {
 
 fn assert_invoc(slice: &mut &[TokenTree]) {
     match &slice[0] {
-        TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
+        TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
         _ => panic!("expected '#' char"),
     }
     match &slice[1] {
@@ -118,11 +118,11 @@ fn assert_invoc(slice: &mut &[TokenTree]) {
 
 fn assert_foo(slice: &mut &[TokenTree]) {
     match &slice[0] {
-        TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "fn"),
+        TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "fn"),
         _ => panic!("expected fn"),
     }
     match &slice[1] {
-        TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "foo"),
+        TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "foo"),
         _ => panic!("expected foo"),
     }
     match &slice[2] {
@@ -148,8 +148,8 @@ fn fold_tree(input: TokenTree) -> TokenTree {
         TokenTree::Group(b) => {
             TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
         }
-        TokenTree::Op(b) => TokenTree::Op(b),
-        TokenTree::Term(a) => TokenTree::Term(a),
+        TokenTree::Punct(b) => TokenTree::Punct(b),
+        TokenTree::Ident(a) => TokenTree::Ident(a),
         TokenTree::Literal(a) => {
             if a.to_string() != "\"foo\"" {
                 TokenTree::Literal(a)
index 10da846a86c5f1e593249e4249ab0bac35d9b8d6..e1a7ffaa26cb7851a3b31117fc7a299b78806661 100644 (file)
@@ -11,7 +11,6 @@
 // force-host
 // no-prefer-dynamic
 
-#![feature(proc_macro, proc_macro_lib)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs
new file mode 100644 (file)
index 0000000..7d36517
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro, proc_macro_lib)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Derive)]
+pub fn derive(_: TokenStream) -> TokenStream {
+    let code = "
+        fn one(r: Restricted) {
+            r.field;
+        }
+        fn two(r: Restricted) {
+            r.field;
+        }
+    ";
+
+    code.parse().unwrap()
+}
index 1d645a7ec510fe420509ea39d600d30c06544218..2d843d0e466525784b466b8125b6df32d2079c26 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:issue_38586.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate issue_38586;
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs
new file mode 100644 (file)
index 0000000..51112f2
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue_50493.rs
+// ignore-stage1
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate issue_50493;
+
+#[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private
+struct Restricted {
+    pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules
+}
+
+mod restricted {}
+
+fn main() {}
+
index c7be316794746c9f04fe63345dcfe03b6213e0a3..98e50183097cce111dae113a677ad97defa18c50 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:bang_proc_macro2.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 #![allow(unused_macros)]
 
 extern crate bang_proc_macro2;
index f16ca79ca9313a9c6dcb4db6c8e589feffc9982e..be5b8c39f1ddecc802971392ee759e376459916b 100644 (file)
@@ -10,7 +10,7 @@
 
 // aux-build:bang_proc_macro.rs
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 #[macro_use]
 extern crate bang_proc_macro;
index a1a15afecd50695d97bd40154997f93e3bd1b18c..ef6d4557f4cd746f7b59c6e107739929469fd91f 100644 (file)
@@ -10,7 +10,7 @@
 
 // aux-build:proc-macro-gates.rs
 
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(use_extern_macros, stmt_expr_attributes)]
 
 extern crate proc_macro_gates as foo;
 
diff --git a/src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs b/src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs
new file mode 100644 (file)
index 0000000..d26ab6d
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+// intentionally empty
index 62ff09f4616b80c7268bcefeb6aa954c1132a6fc..8b4e2c3c051e85c618c92d7c6b6a96b59717bd47 100644 (file)
@@ -56,9 +56,8 @@ fn call_foo_f() {
 }
 
 fn array_a() {
-    // Accepted: return is coerced to `!` just fine, and then `22` can be
-    // because we already diverged.
-    let x: [!; 2] = [return, 22];
+    // Return is coerced to `!` just fine, but `22` cannot be.
+    let x: [!; 2] = [return, 22]; //~ ERROR mismatched types
 }
 
 fn array_b() {
index b034fedb805e343b85ae4024275185aa8f033a70..d437fc019fda04f5ccec10d0d72548eb96a52445 100644 (file)
 // Check that when there are vacuous predicates in the environment
 // (which make a fn uncallable) we don't erroneously cache those and
 // then consider them satisfied elsewhere. The current technique for
-// doing this is just to filter "global" predicates out of the
-// environment, which means that we wind up with an error in the
-// function `vacuous`, because even though `i32: Bar<u32>` is implied
-// by its where clause, that where clause never holds.
+// doing this is to not use global caches when there is a chance that
+// the environment contains such a predicate.
+// We still error for `i32: Bar<u32>` pending #48214
 
 trait Foo<X,Y>: Bar<X> {
 }
index dcf02f308307d0b97c5d93c3161938a690664c0f..a5df717e06ba91401e86ed83f43d9ac2d04fc3f4 100644 (file)
 enum Enum {
    A {
      x: Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
    }
 }
 
index 7eb44c7e19e84a7d88a1bf874ffcc42394af2343..3411d2f3119ec4af87418e9297bbd015bde6b29c 100644 (file)
 enum Enum {
    A(
      Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
      )
 }
 
index 36dae0124ce9bf410f872bc12823240e778ab9f7..1feadc2fd83b5c2b4ef0472b413449dcc389f8d4 100644 (file)
 #[derive(PartialOrd,PartialEq)]
 struct Struct {
     x: Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
 }
 
 fn main() {}
index fd2df0967545b9eb23b9a0be7e52787b84376cb0..9db0fed2d9e9d543dd4688ae5516e55afd55bf35 100644 (file)
 #[derive(PartialOrd,PartialEq)]
 struct Struct(
     Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
 );
 
 fn main() {}
diff --git a/src/test/compile-fail/edition-extern-crate-allowed.rs b/src/test/compile-fail/edition-extern-crate-allowed.rs
new file mode 100644 (file)
index 0000000..286ee89
--- /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.
+
+// aux-build:edition-extern-crate-allowed.rs
+// compile-flags: --edition 2015
+// compile-pass
+
+#![deny(rust_2018_idioms)]
+
+extern crate edition_extern_crate_allowed;
+
+fn main() {}
diff --git a/src/test/compile-fail/edition-feature-ok.rs b/src/test/compile-fail/edition-feature-ok.rs
new file mode 100644 (file)
index 0000000..3a3a6ff
--- /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.
+
+// compile-flags:--edition 2018
+// compile-pass
+
+#![feature(rust_2018_preview)]
+
+fn main() {}
index 10622eccbdcd19d9a47000d82a1661571bca80cb..b07c23c3fc72da5ec4721be552483a4e80178305 100644 (file)
@@ -17,7 +17,7 @@ impl<T, Smoke> Mirror<Smoke> for T {
 }
 
 pub fn poison<S>(victim: String) where <String as Mirror<S>>::Image: Copy {
-    loop { drop(victim); } //~ ERROR use of moved value
+    loop { drop(victim); }
 }
 
 fn main() {
index df766e361d5bdb553c8f62f2ca218495d80d1856..32f9b83b6e2c77f556439d8e5cbf4851f1ecca11 100644 (file)
@@ -15,35 +15,21 @@ struct AllTheRanges {
     a: Range<usize>,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
     b: RangeTo<usize>,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
     c: RangeFrom<usize>,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
     d: RangeFull,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
     e: RangeInclusive<usize>,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
     f: RangeToInclusive<usize>,
     //~^ ERROR PartialOrd
     //~^^ ERROR Ord
-    //~^^^ ERROR binary operation `<` cannot be applied to type
-    //~^^^^ ERROR binary operation `>` cannot be applied to type
-    //~^^^^^ ERROR binary operation `<=` cannot be applied to type
-    //~^^^^^^ ERROR binary operation `>=` cannot be applied to type
 }
 
 fn main() {}
diff --git a/src/test/run-make-fulldeps/issue-36710/Makefile b/src/test/run-make-fulldeps/issue-36710/Makefile
new file mode 100644 (file)
index 0000000..2cb0b4c
--- /dev/null
@@ -0,0 +1,12 @@
+-include ../tools.mk
+
+all: foo
+       $(call RUN,foo)
+
+foo: foo.rs $(call NATIVE_STATICLIB,foo)
+       $(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
+
+$(TMPDIR)/libfoo.o: foo.cpp
+       $(call COMPILE_OBJ_CXX,$@,$<)
+
+.PHONY: all
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.cpp b/src/test/run-make-fulldeps/issue-36710/foo.cpp
new file mode 100644 (file)
index 0000000..fbd0ead
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+#include <stdint.h>
+
+struct A {
+    A() { v = 1234; }
+    ~A() { v = 1; }
+    uint32_t v;
+};
+
+A a;
+
+extern "C" {
+    uint32_t get() {
+        return a.v;
+    }
+}
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.rs b/src/test/run-make-fulldeps/issue-36710/foo.rs
new file mode 100644 (file)
index 0000000..6e50566
--- /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.
+
+// Tests that linking to C++ code with global destructors works.
+
+extern { fn get() -> u32; }
+
+fn main() {
+    let i = unsafe { get() };
+    assert_eq!(i, 1234);
+}
index af1707de6c02f52432cfc241cca0df4f9e06ad70..3de358fa50007140e480d160ec4b66e01d70d08d 100644 (file)
@@ -59,12 +59,14 @@ endif
 
 ifdef IS_MSVC
 COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
 NATIVE_STATICLIB_FILE = $(1).lib
 NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
 OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
        -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
 else
 COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
 NATIVE_STATICLIB_FILE = lib$(1).a
 NATIVE_STATICLIB = $(call STATICLIB,$(1))
 OUT_EXE=-o $(TMPDIR)/$(1)
index 98b509cd81f5453e204d4625be5869acb619ee31..925f686fe1161bb4b036d59ee257a2d30124e697 100644 (file)
@@ -18,9 +18,9 @@ endif
 OBJDUMP=llvm-objdump
 SECTION_HEADERS=$(OBJDUMP) -section-headers
 
-BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
+BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
 
-BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
+BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
 
 all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
 
index de26f8296e36b513f9e415165aa9311f92bd201f..ec6f54fb1378f4d703bf1cb33edec5b78da1f725 100644 (file)
@@ -33,7 +33,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
             panic!("Invalid macro usage in cond: {}", cond);
         }
         let is_else = match test {
-            TokenTree::Term(word) => &*word.to_string() == "else",
+            TokenTree::Ident(ref word) => &*word.to_string() == "else",
             _ => false,
         };
         conds.push(if is_else || input.peek().is_none() {
index a680698df9a2a11cd23b3d637665793ea3f06eac..f026d8e2365d9953ebc1b07ca2e6a88bf87379fe 100644 (file)
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
+#![feature(proc_macro, proc_macro_non_items)]
 
 extern crate proc_macro;
 
index a280b3d87c68508262ba481fec353dfed4fc03d3..9a5bffb92a4937112106c1fc937781d858df5d29 100644 (file)
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
+#![feature(proc_macro, proc_macro_non_items)]
 
 extern crate proc_macro;
 
index 52e8e75f2628e2297c238ab48468fc6a7aa98eee..f1dcec8af6906a5478fabcce97cc7a8c58a690fe 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:cond_plugin.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate cond_plugin;
 
index f359735d2f77047f7616bd343acde4544fb2cb95..1f6a340c7e88bd93ace0b5e1b880cbc7a37581f2 100644 (file)
@@ -13,7 +13,7 @@
 // aux-build:hello_macro.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate hello_macro;
 
index 5376d2740452fb1ae053f21a5162340312c5dcfb..55c4c32a94d80c8e85610cac5db99fa98cec606c 100644 (file)
@@ -28,7 +28,7 @@ fn count_compound_ops_helper(input: TokenStream) -> u32 {
     let mut count = 0;
     for token in input {
         match &token {
-            TokenTree::Op(tt) if tt.spacing() == Spacing::Alone => {
+            TokenTree::Punct(tt) if tt.spacing() == Spacing::Alone => {
                 count += 1;
             }
             TokenTree::Group(tt) => {
index 787a4a470e257df84c3e3ba815572e1adcb2d1de..2b413579a9a0f4387ff64e9f5679db2101b050e5 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // no-prefer-dynamic
-#![feature(proc_macro)]
+
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
index 8ffa7abe6f7f943e35f6029ef74679df939c0b92..bac6524847a887f30f68918e2d398df5cee80a0f 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
 
 extern crate hygiene_example_codegen;
 
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs
new file mode 100644 (file)
index 0000000..f31f57b
--- /dev/null
@@ -0,0 +1,36 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn lifetimes_bang(input: TokenStream) -> TokenStream {
+    // Roundtrip through token trees
+    input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn lifetimes_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+    // Roundtrip through AST
+    input
+}
+
+#[proc_macro_derive(Lifetimes)]
+pub fn lifetimes_derive(input: TokenStream) -> TokenStream {
+    // Roundtrip through a string
+    format!("mod m {{ {} }}", input).parse().unwrap()
+}
index 6f8c649c6b56cfe22a56ea6baef5434953b4c95b..fb505755792321d7d3b156816daca4d96d8a449a 100644 (file)
@@ -38,14 +38,14 @@ fn assert_eq(a: TokenStream, b: TokenStream) {
                 assert_eq!(a.delimiter(), b.delimiter());
                 assert_eq(a.stream(), b.stream());
             }
-            (TokenTree::Op(a), TokenTree::Op(b)) => {
-                assert_eq!(a.op(), b.op());
+            (TokenTree::Punct(a), TokenTree::Punct(b)) => {
+                assert_eq!(a.as_char(), b.as_char());
                 assert_eq!(a.spacing(), b.spacing());
             }
             (TokenTree::Literal(a), TokenTree::Literal(b)) => {
                 assert_eq!(a.to_string(), b.to_string());
             }
-            (TokenTree::Term(a), TokenTree::Term(b)) => {
+            (TokenTree::Ident(a), TokenTree::Ident(b)) => {
                 assert_eq!(a.to_string(), b.to_string());
             }
             (a, b) => panic!("{:?} != {:?}", a, b),
index 82337022ac3bf4ddf910e92f293b0a21e656b175..f9d17a9decbb6b5134775e8f0ca018dfdfb9f02f 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:bang-macro.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate bang_macro;
 use bang_macro::rewrite;
index 3fbe5366b6a1b839b88656176ed19b9a85c3099f..f4a51d0624ae6152af9ed255e8abda7eb365d3ba 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:count_compound_ops.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate count_compound_ops;
 use count_compound_ops::count_compound_ops;
index b94c45248dae524d2b779b968200ea4ac618c7a2..6ef23bc772b5c26ab5cbce89ba9dfb1f2bcff5fe 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:derive-attr-cfg.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
 
 extern crate derive_attr_cfg;
 use derive_attr_cfg::Foo;
index 48de15b934d23d679a2573bf0ca148c9760a87fe..5ee164415a1a583770f2f6aa1a21e674483e27e3 100644 (file)
@@ -12,7 +12,7 @@
 // aux-build:hygiene_example.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate hygiene_example;
 use hygiene_example::hello;
index 87130242c0f04035331fda007066e1f0ee9af507..5b7d8c2b05b69123bcf4c6d3929ba9225070d7b3 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:issue-39889.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
 #![allow(unused)]
 
 extern crate issue_39889;
index b7826edd8b4e5215c82aba9325d639a82cf2935e..b828199883fa081108077eb6560e0d191a858fe5 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:issue-40001-plugin.rs
 // ignore-stage1
 
-#![feature(proc_macro, plugin)]
+#![feature(plugin)]
 #![plugin(issue_40001_plugin)]
 
 #[whitelisted_attr]
diff --git a/src/test/run-pass-fulldeps/proc-macro/lifetimes.rs b/src/test/run-pass-fulldeps/proc-macro/lifetimes.rs
new file mode 100644 (file)
index 0000000..0bcb23c
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lifetimes.rs
+// ignore-stage1
+
+#![feature(proc_macro)]
+
+extern crate lifetimes;
+use lifetimes::*;
+
+lifetimes_bang! {
+    fn bang<'a>() -> &'a u8 { &0 }
+}
+
+#[lifetimes_attr]
+fn attr<'a>() -> &'a u8 { &1 }
+
+#[derive(Lifetimes)]
+pub struct Lifetimes<'a> {
+    pub field: &'a u8,
+}
+
+fn main() {
+    assert_eq!(bang::<'static>(), &0);
+    assert_eq!(attr::<'static>(), &1);
+    let l1 = Lifetimes { field: &0 };
+    let l2 = m::Lifetimes { field: &1 };
+}
index 1cdf1daf560835af0b9775feaeee6a981421619c..a793d069d1448b8551eca130d8258daaf4a55d1a 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:negative-token.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate negative_token;
 
index c2df561b43a114a405b431d78b053f7512d5b552..735e088b82a50354f72812dcda1e4949fb7d5522 100644 (file)
@@ -13,7 +13,7 @@
 
 // ignore-pretty
 
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
 
 #[macro_use]
 extern crate span_test_macros;
index 914b89dfb4dc030ae81190b79d525f51eaed8b7e..2d478e954e7cb7cb493e98b9da4e2ad124f80b33 100644 (file)
@@ -15,7 +15,7 @@
 
 struct SlowFmt(u32);
 impl fmt::Debug for SlowFmt {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         thread::sleep_ms(3);
         self.0.fmt(f)
     }
diff --git a/src/test/run-pass/impl-trait/issue-49376.rs b/src/test/run-pass/impl-trait/issue-49376.rs
new file mode 100644 (file)
index 0000000..b687b48
--- /dev/null
@@ -0,0 +1,29 @@
+// 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 for nested self-reference which caused a stack overflow.
+
+use std::fmt::Debug;
+use std::ops::*;
+
+fn gen() -> impl PartialOrd + PartialEq + Debug { }
+
+struct Bar {}
+trait Foo<T = Self> {}
+impl Foo for Bar {}
+
+fn foo() -> impl Foo {
+    Bar {}
+}
+
+fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 }
+fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 }
+
+fn main() {}
index 235d3982a9c0c897f7dfd8c3127d40cb8206e656..92f68dcfc349de1a7fbc5a088c57394c78692aa1 100644 (file)
@@ -24,6 +24,7 @@ union Foo {
 }
 
 // If all the variants are uninhabited, however, the union should be uninhabited.
+// NOTE(#49298) the union being uninhabited shouldn't change its size.
 union Bar {
     _a: (Never, u64),
     _b: (u64, Never)
@@ -31,7 +32,8 @@ union Bar {
 
 fn main() {
     assert_eq!(mem::size_of::<Foo>(), 8);
-    assert_eq!(mem::size_of::<Bar>(), 0);
+    // See the note on `Bar`'s definition for why this isn't `0`.
+    assert_eq!(mem::size_of::<Bar>(), 8);
 
     let f = [Foo { a: 42 }, Foo { a: 10 }];
     println!("{}", unsafe { f[0].a });
diff --git a/src/test/run-pass/issue-49298.rs b/src/test/run-pass/issue-49298.rs
new file mode 100644 (file)
index 0000000..0b2169c
--- /dev/null
@@ -0,0 +1,34 @@
+// 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(test)]
+
+extern crate test;
+
+enum Void {}
+
+fn main() {
+    let mut x: (Void, usize);
+    let mut y = 42;
+    x.1 = 13;
+
+    // Make sure `y` stays on the stack.
+    test::black_box(&mut y);
+
+    // Check that the write to `x.1` did not overwrite `y`.
+    // Note that this doesn't fail with optimizations enabled,
+    // because we can't keep `x.1` on the stack, like we can `y`,
+    // as we can't borrow partially initialized variables.
+    assert_eq!(y.to_string(), "42");
+
+    // Check that `(Void, usize)` has space for the `usize` field.
+    assert_eq!(std::mem::size_of::<(Void, usize)>(),
+               std::mem::size_of::<usize>());
+}
diff --git a/src/test/run-pass/issue-50442.rs b/src/test/run-pass/issue-50442.rs
new file mode 100644 (file)
index 0000000..1e43beb
--- /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.
+
+enum Void {}
+
+enum Foo {
+    A(i32),
+    B(Void),
+    C(i32)
+}
+
+fn main() {
+    let _foo = Foo::A(0);
+}
diff --git a/src/test/run-pass/issue-50731.rs b/src/test/run-pass/issue-50731.rs
new file mode 100644 (file)
index 0000000..06df2b9
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 Void {}
+fn foo(_: Result<(Void, u32), (Void, String)>) {}
+fn main() {
+    let _: fn(_) = foo;
+}
index b0c9280b6ce44fb3effe9cf291f64f24296d79a7..b9e1fde6b1f3e10efb0ea203e6ad4ee7d52ca39d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(macro_lifetime_matcher)]
-
 macro_rules! foo {
     ($l:lifetime, $l2:lifetime) => {
         fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str {
index 8a2d76e17df6846ada9f4cccd751b70c167ed81e..d003d7dcfb6206ba75ba87e51cfc12edac19a2ce 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![allow(unreachable_code)]
-#![feature(macro_lifetime_matcher)]
 
 macro_rules! x {
     ($a:lifetime) => {
index 468ee2e94365723690f85f750b1467be8bb9eea1..5c1f8683e00f600a6c165f660265a8f4931c57fe 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(macro_lifetime_matcher)]
-
 macro_rules! foo {
     ($l:lifetime) => {
         fn f(arg: &$l str) -> &$l str {
index db521ca7f103fb74d101fc830bf35e9254e0f9c0..ff5798ff78d62837e9c475c21296a7577786775c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(macro_lifetime_matcher)]
-
 macro_rules! foo {
     ($l:lifetime) => {
         fn f<$l>(arg: &$l str) -> &$l str {
diff --git a/src/test/run-pass/macro-literal.rs b/src/test/run-pass/macro-literal.rs
new file mode 100644 (file)
index 0000000..0bcda7b
--- /dev/null
@@ -0,0 +1,143 @@
+// 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(macro_literal_matcher)]
+
+macro_rules! mtester {
+    ($l:literal) => {
+        &format!("macro caught literal: {}", $l)
+    };
+    ($e:expr) => {
+        &format!("macro caught expr: {}", $e)
+    };
+}
+
+macro_rules! two_negative_literals {
+    ($l1:literal $l2:literal) => {
+        &format!("macro caught literals: {}, {}", $l1, $l2)
+    };
+}
+
+macro_rules! only_expr {
+    ($e:expr) => {
+        &format!("macro caught expr: {}", $e)
+    };
+}
+
+macro_rules! mtester_dbg {
+    ($l:literal) => {
+        &format!("macro caught literal: {:?}", $l)
+    };
+    ($e:expr) => {
+        &format!("macro caught expr: {:?}", $e)
+    };
+}
+
+macro_rules! catch_range {
+    ($s:literal ... $e:literal) => {
+        &format!("macro caught literal: {} ... {}", $s, $e)
+    };
+    (($s:expr) ... ($e:expr)) => { // Must use ')' before '...'
+        &format!("macro caught expr: {} ... {}", $s, $e)
+    };
+}
+
+macro_rules! pat_match {
+    ($s:literal ... $e:literal) => {
+        match 3 {
+            $s ... $e => "literal, in range",
+            _ => "literal, other",
+        }
+    };
+    ($s:pat) => {
+        match 3 {
+            $s => "pat, single",
+            _ => "pat, other",
+        }
+    };
+}
+
+macro_rules! match_attr {
+    (#[$attr:meta] $e:literal) => {
+        "attr matched literal"
+    };
+    (#[$attr:meta] $e:expr) => {
+        "attr matched expr"
+    };
+}
+
+macro_rules! match_produced_attr {
+    ($lit: literal) => {
+        // Struct with doc comment passed via $literal
+        #[doc = $lit]
+        struct LiteralProduced;
+    };
+    ($expr: expr) => {
+        struct ExprProduced;
+    };
+}
+
+macro_rules! test_user {
+    ($s:literal, $e:literal) => {
+        {
+            let mut v = Vec::new();
+            for i in $s .. $e {
+                v.push(i);
+            }
+            "literal"
+        }
+    };
+    ($s:expr, $e: expr) => {
+        {
+            let mut v = Vec::new();
+            for i in $s .. $e {
+                v.push(i);
+            }
+            "expr"
+        }
+    };
+}
+
+pub fn main() {
+    // Cases where 'literal' catches
+    assert_eq!(mtester!("str"), "macro caught literal: str");
+    assert_eq!(mtester!(2), "macro caught literal: 2");
+    assert_eq!(mtester!(2.2), "macro caught literal: 2.2");
+    assert_eq!(mtester!(1u32), "macro caught literal: 1");
+    assert_eq!(mtester!(0x32), "macro caught literal: 50");
+    assert_eq!(mtester!('c'), "macro caught literal: c");
+    assert_eq!(mtester!(-1.2), "macro caught literal: -1.2");
+    assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3");
+    assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3");
+    assert_eq!(match_attr!(#[attr] 1), "attr matched literal");
+    assert_eq!(test_user!(10, 20), "literal");
+    assert_eq!(mtester!(false), "macro caught literal: false");
+    assert_eq!(mtester!(true), "macro caught literal: true");
+    match_produced_attr!("a");
+    let _a = LiteralProduced;
+    assert_eq!(pat_match!(1 ... 3), "literal, in range");
+    assert_eq!(pat_match!(4 ... 6), "literal, other");
+
+    // Cases where 'expr' catches
+    assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2");
+    assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2");
+    assert_eq!(mtester!((1 + 3)), "macro caught expr: 4");
+    assert_eq!(mtester_dbg!(()), "macro caught expr: ()");
+    assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4");
+    assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr");
+    assert_eq!(test_user!(10, (20 + 2)), "expr");
+
+    match_produced_attr!((3 + 2));
+    let _b = ExprProduced;
+
+    // Cases where 'pat' matched
+    assert_eq!(pat_match!(3), "pat, single");
+    assert_eq!(pat_match!(6), "pat, other");
+}
index a47f082b9c3ee8baa53644f840bc9b8b635c8cc0..8f4613d6c373a0c0eae06c81cbeab5740284eac6 100644 (file)
@@ -68,9 +68,15 @@ enum EnumSingle5 {
     A = 42 as u8,
 }
 
-enum NicheFilledEnumWithInhabitedVariant {
+enum EnumWithMaybeUninhabitedVariant<T> {
     A(&'static ()),
-    B(&'static (), !),
+    B(&'static (), T),
+    C,
+}
+
+enum NicheFilledEnumWithAbsentVariant {
+    A(&'static ()),
+    B((), !),
     C,
 }
 
@@ -107,5 +113,7 @@ pub fn main() {
     assert_eq!(size_of::<EnumSingle4>(), 1);
     assert_eq!(size_of::<EnumSingle5>(), 1);
 
-    assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>());
+    assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
+               size_of::<EnumWithMaybeUninhabitedVariant<()>>());
+    assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
 }
index 1cdaff2cab7c8c7e25efe55464f7744d03fdf8d3..c1e408cc02ac6764aa95fc848f28fe26ddcf4549 100644 (file)
@@ -15,7 +15,7 @@ union U {
 }
 
 impl fmt::Display for U {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         unsafe { write!(f, "Oh hai {}", self.a) }
     }
 }
diff --git a/src/test/rustdoc-js/deduplication.js b/src/test/rustdoc-js/deduplication.js
new file mode 100644 (file)
index 0000000..0f29607
--- /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.
+
+// ignore-order
+
+const QUERY = 'is_nan';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::f32', 'name': 'is_nan' },
+        { 'path': 'std::f64', 'name': 'is_nan' },
+        { 'path': 'std::option::Option', 'name': 'is_none' },
+    ],
+};
diff --git a/src/test/rustdoc/pub-restricted.rs b/src/test/rustdoc/pub-restricted.rs
new file mode 100644 (file)
index 0000000..cc8f628
--- /dev/null
@@ -0,0 +1,44 @@
+// 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
+
+// compile-flags: --document-private-items
+
+#![feature(crate_visibility_modifier)]
+
+#![crate_name = "foo"]
+
+// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic'
+pub struct FooPublic;
+// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate'
+crate struct FooJustCrate;
+// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate'
+pub(crate) struct FooPubCrate;
+// @has 'foo/struct.FooSelf.html' '//pre' 'pub(self) struct FooSelf'
+pub(self) struct FooSelf;
+// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(self) struct FooInSelf'
+pub(in self) struct FooInSelf;
+mod a {
+    // @has 'foo/a/struct.FooSuper.html' '//pre' 'pub(super) struct FooSuper'
+    pub(super) struct FooSuper;
+    // @has 'foo/a/struct.FooInSuper.html' '//pre' 'pub(super) struct FooInSuper'
+    pub(in super) struct FooInSuper;
+    // @has 'foo/a/struct.FooInA.html' '//pre' 'pub(in a) struct FooInA'
+    pub(in a) struct FooInA;
+    mod b {
+        // @has 'foo/a/b/struct.FooInSelfSuperB.html' '//pre' 'pub(in self::super::b) struct FooInSelfSuperB'
+        pub(in self::super::b) struct FooInSelfSuperB;
+        // @has 'foo/a/b/struct.FooInSuperSuper.html' '//pre' 'pub(in super::super) struct FooInSuperSuper'
+        pub(in super::super) struct FooInSuperSuper;
+        // @has 'foo/a/b/struct.FooInAB.html' '//pre' 'pub(in a::b) struct FooInAB'
+        pub(in a::b) struct FooInAB;
+    }
+}
diff --git a/src/test/ui-fulldeps/auxiliary/invalid-punct-ident.rs b/src/test/ui-fulldeps/auxiliary/invalid-punct-ident.rs
new file mode 100644 (file)
index 0000000..6bdfe5f
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn invalid_punct(_: TokenStream) -> TokenStream {
+    TokenTree::from(Punct::new('`', Spacing::Alone)).into()
+}
+
+#[proc_macro]
+pub fn invalid_ident(_: TokenStream) -> TokenStream {
+    TokenTree::from(Ident::new("*", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn invalid_raw_ident(_: TokenStream) -> TokenStream {
+    TokenTree::from(Ident::new_raw("self", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn lexer_failure(_: TokenStream) -> TokenStream {
+    "a b ) c".parse().expect("parsing failed without panic")
+}
diff --git a/src/test/ui-fulldeps/auxiliary/lifetimes.rs b/src/test/ui-fulldeps/auxiliary/lifetimes.rs
new file mode 100644 (file)
index 0000000..ecf0a56
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn single_quote_alone(_: TokenStream) -> TokenStream {
+    // `&'a u8`, but the `'` token is not joint
+    let trees: Vec<TokenTree> = vec![
+        Punct::new('&', Spacing::Alone).into(),
+        Punct::new('\'', Spacing::Alone).into(),
+        Ident::new("a", Span::call_site()).into(),
+        Ident::new("u8", Span::call_site()).into(),
+    ];
+    trees.into_iter().collect()
+}
index c5ba2aa9413e7f8d0adbf5f054119bd6d3960012..7be909c3c9e87f6a4322719fa241f0a3fe989fc8 100644 (file)
@@ -11,7 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
 
 extern crate proc_macro;
 
index 4fd87632067331ac95e8cb1600b4940fc296e0da..5ec79a5520009a27c7801afd12a7925d86adcb6f 100644 (file)
@@ -11,8 +11,6 @@
 // aux-build:plugin.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use] extern crate plugin;
 
 #[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked
index 0278256994120983eb1ec8b64a9a97be5a65aa55..ecbe0a9a0c079e04e655428c9bb136c7b5546ab2 100644 (file)
@@ -1,5 +1,5 @@
 error: proc-macro derive panicked
-  --> $DIR/issue-36935.rs:18:15
+  --> $DIR/issue-36935.rs:16:15
    |
 LL | #[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked
    |               ^^^
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-1.rs b/src/test/ui-fulldeps/invalid-punct-ident-1.rs
new file mode 100644 (file)
index 0000000..576c156
--- /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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_punct!(); //~ ERROR proc macro panicked
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-1.stderr b/src/test/ui-fulldeps/invalid-punct-ident-1.stderr
new file mode 100644 (file)
index 0000000..3b3619e
--- /dev/null
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/invalid-punct-ident-1.rs:16:1
+   |
+LL | invalid_punct!(); //~ ERROR proc macro panicked
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: message: unsupported character `'`'`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-2.rs b/src/test/ui-fulldeps/invalid-punct-ident-2.rs
new file mode 100644 (file)
index 0000000..874a7d1
--- /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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_ident!(); //~ ERROR proc macro panicked
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-2.stderr b/src/test/ui-fulldeps/invalid-punct-ident-2.stderr
new file mode 100644 (file)
index 0000000..869c090
--- /dev/null
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/invalid-punct-ident-2.rs:16:1
+   |
+LL | invalid_ident!(); //~ ERROR proc macro panicked
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: message: `"*"` is not a valid identifier
+
+error: aborting due to previous error
+
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-3.rs b/src/test/ui-fulldeps/invalid-punct-ident-3.rs
new file mode 100644 (file)
index 0000000..f73bf50
--- /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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_raw_ident!(); //~ ERROR proc macro panicked
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-3.stderr b/src/test/ui-fulldeps/invalid-punct-ident-3.stderr
new file mode 100644 (file)
index 0000000..716f6ff
--- /dev/null
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/invalid-punct-ident-3.rs:16:1
+   |
+LL | invalid_raw_ident!(); //~ ERROR proc macro panicked
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: message: `"self"` is not a valid raw identifier
+
+error: aborting due to previous error
+
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-4.rs b/src/test/ui-fulldeps/invalid-punct-ident-4.rs
new file mode 100644 (file)
index 0000000..1e93c69
--- /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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+lexer_failure!(); //~ ERROR proc macro panicked
+                  //~| ERROR unexpected close delimiter: `)`
diff --git a/src/test/ui-fulldeps/invalid-punct-ident-4.stderr b/src/test/ui-fulldeps/invalid-punct-ident-4.stderr
new file mode 100644 (file)
index 0000000..4493e37
--- /dev/null
@@ -0,0 +1,14 @@
+error: unexpected close delimiter: `)`
+  --> $DIR/invalid-punct-ident-4.rs:16:1
+   |
+LL | lexer_failure!(); //~ ERROR proc macro panicked
+   | ^^^^^^^^^^^^^^^^^
+
+error: proc macro panicked
+  --> $DIR/invalid-punct-ident-4.rs:16:1
+   |
+LL | lexer_failure!(); //~ ERROR proc macro panicked
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui-fulldeps/lifetimes.rs b/src/test/ui-fulldeps/lifetimes.rs
new file mode 100644 (file)
index 0000000..6e88143
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lifetimes.rs
+
+#![feature(proc_macro, proc_macro_non_items)]
+
+extern crate lifetimes;
+
+use lifetimes::*;
+
+type A = single_quote_alone!(); //~ ERROR expected type, found `'`
diff --git a/src/test/ui-fulldeps/lifetimes.stderr b/src/test/ui-fulldeps/lifetimes.stderr
new file mode 100644 (file)
index 0000000..6baf2b1
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected type, found `'`
+  --> $DIR/lifetimes.rs:19:10
+   |
+LL | type A = single_quote_alone!(); //~ ERROR expected type, found `'`
+   |          ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index fda0e28891f26b0712f7b264f3b8070a8348e100..8dfb9cb4fb751b6e971fa4d24379b36597db4b6a 100644 (file)
@@ -27,8 +27,8 @@ fn parse(input: TokenStream) -> Result<(), Diagnostic> {
                            .help("input must be: `===`"))
         }
 
-        if let TokenTree::Op(tt) = tree {
-            if tt.op() == '=' {
+        if let TokenTree::Punct(ref tt) = tree {
+            if tt.as_char() == '=' {
                 count += 1;
                 last_span = span;
                 continue
index f938700e5157a282bf8950612845b07895a24981..a60841d848c16363ac56f08e03cd04abf7d2e858 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:parent-source-spans.rs
 // ignore-stage1
 
-#![feature(proc_macro, decl_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
 
 extern crate parent_source_spans;
 
index 66e34afcb13f92220644a8885f310021369ac1df..ee5f3b33a0648c739473f33c12a4aac83985a6cd 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:three-equals.rs
 // ignore-stage1
 
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
 
 extern crate three_equals;
 
index ae94a7f13e23e9ab2bad13b21a409c3542ccd6db..9cc825fcddd7afad40c7cdcf1e1cda99a4dd1f72 100644 (file)
@@ -14,7 +14,6 @@
 // aux-build:bang_proc_macro.rs
 
 #![feature(proc_macro)]
-#![allow(unused_macros)]
 
 #[macro_use]
 extern crate derive_foo;
index e19ec9e6f803caba63b24c657f5224316b8317e3..caa7966461487211532de3f7e9d41194b2c283bf 100644 (file)
@@ -1,59 +1,59 @@
 error: cannot find derive macro `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:37:10
+  --> $DIR/resolve-error.rs:36:10
    |
 LL | #[derive(FooWithLongNan)]
    |          ^^^^^^^^^^^^^^ help: try: `FooWithLongName`
 
 error: cannot find attribute macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:41:3
+  --> $DIR/resolve-error.rs:40:3
    |
 LL | #[attr_proc_macra]
    |   ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro`
 
 error: cannot find attribute macro `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:45:3
+  --> $DIR/resolve-error.rs:44:3
    |
 LL | #[FooWithLongNan]
    |   ^^^^^^^^^^^^^^
 
 error: cannot find derive macro `Dlone` in this scope
-  --> $DIR/resolve-error.rs:49:10
+  --> $DIR/resolve-error.rs:48:10
    |
 LL | #[derive(Dlone)]
    |          ^^^^^ help: try: `Clone`
 
 error: cannot find derive macro `Dlona` in this scope
-  --> $DIR/resolve-error.rs:53:10
+  --> $DIR/resolve-error.rs:52:10
    |
 LL | #[derive(Dlona)]
    |          ^^^^^ help: try: `Clona`
 
 error: cannot find derive macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:57:10
+  --> $DIR/resolve-error.rs:56:10
    |
 LL | #[derive(attr_proc_macra)]
    |          ^^^^^^^^^^^^^^^
 
 error: cannot find macro `FooWithLongNama!` in this scope
-  --> $DIR/resolve-error.rs:62:5
+  --> $DIR/resolve-error.rs:61:5
    |
 LL |     FooWithLongNama!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam`
 
 error: cannot find macro `attr_proc_macra!` in this scope
-  --> $DIR/resolve-error.rs:65:5
+  --> $DIR/resolve-error.rs:64:5
    |
 LL |     attr_proc_macra!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac`
 
 error: cannot find macro `Dlona!` in this scope
-  --> $DIR/resolve-error.rs:68:5
+  --> $DIR/resolve-error.rs:67:5
    |
 LL |     Dlona!();
    |     ^^^^^
 
 error: cannot find macro `bang_proc_macrp!` in this scope
-  --> $DIR/resolve-error.rs:71:5
+  --> $DIR/resolve-error.rs:70:5
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro`
index 9d678d91578bc1027db26cba228d1a80489178ae..0f532d3da6a7307ad1f25993bb5705ee3be751c4 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: --edition 2018
+
 #![deny(unnecessary_extern_crate)]
 #![feature(alloc, test, libc)]
 
index 7718808be58baea95df41a1088ea3bc83028fecd..ab5457018eda66d9e0a068faa17919396fd78062 100644 (file)
@@ -1,68 +1,68 @@
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:14:1
+  --> $DIR/unnecessary-extern-crate.rs:16:1
    |
 LL | extern crate alloc;
    | ^^^^^^^^^^^^^^^^^^^ help: remove it
    |
 note: lint level defined here
-  --> $DIR/unnecessary-extern-crate.rs:11:9
+  --> $DIR/unnecessary-extern-crate.rs:13:9
    |
 LL | #![deny(unnecessary_extern_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:17:1
+  --> $DIR/unnecessary-extern-crate.rs:19:1
    |
 LL | extern crate alloc as x;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:23:1
+  --> $DIR/unnecessary-extern-crate.rs:25:1
    |
 LL | pub extern crate test as y;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:26:1
+  --> $DIR/unnecessary-extern-crate.rs:28:1
    |
 LL | pub extern crate libc;
-   | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
+   | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:32:5
+  --> $DIR/unnecessary-extern-crate.rs:34:5
    |
 LL |     extern crate alloc;
-   |     ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+   |     ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:35:5
+  --> $DIR/unnecessary-extern-crate.rs:37:5
    |
 LL |     extern crate alloc as x;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:38:5
+  --> $DIR/unnecessary-extern-crate.rs:40:5
    |
 LL |     pub extern crate test;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:41:5
+  --> $DIR/unnecessary-extern-crate.rs:43:5
    |
 LL |     pub extern crate test as y;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:45:9
+  --> $DIR/unnecessary-extern-crate.rs:47:9
    |
 LL |         extern crate alloc;
-   |         ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+   |         ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:48:9
+  --> $DIR/unnecessary-extern-crate.rs:50:9
    |
 LL |         extern crate alloc as x;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
 
 error: aborting due to 10 previous errors
 
index 07aa3bfe40dea06e94f2da26f0a40d493b70ed81..c89defa3dd196d97a4a8822a33b37b1a933b527a 100644 (file)
@@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
 LL |         x % 2 == 0
    |         ^^^^^
    |
-   = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work
-   = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+   = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
 
 error: aborting due to previous error
 
index 2c8a33d95c03a23e57839323ea4f1d5feb7afb90..15c159a3b153cf8f8cfcdc586eac03a2dce496ae 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/issue-28308.rs:12:5
    |
 LL |     assert!("foo");
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-eval/duration_conversion.rs b/src/test/ui/const-eval/duration_conversion.rs
new file mode 100644 (file)
index 0000000..4481b75
--- /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.
+
+// compile-pass
+
+#![feature(duration_getters)]
+
+use std::time::Duration;
+
+fn main() {
+    const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000);
+    const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000);
+    const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000);
+    const _ONE_NANOSECOND: Duration = Duration::from_nanos(1);
+    const _ONE: usize = _ONE_SECOND.as_secs() as usize;
+    const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize;
+    const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize;
+    const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize;
+    const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO];
+    const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR];
+}
index 76f06c7c46379476a0cc744d4e5f6d1b4c3d74b7..43e1ca4096cf69a37f9c90006a04ced496241fc9 100644 (file)
@@ -5,6 +5,8 @@ LL |     LinkedList::new() += 1; //~ ERROR E0368
    |     -----------------^^^^^
    |     |
    |     cannot use `+=` on type `std::collections::LinkedList<_>`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
 
 error[E0067]: invalid left-hand side expression
   --> $DIR/E0067.rs:14:5
index 500feb39f5e7421e9cafaa93fc2e3a717d65abc6..c29ec4fe6ae76e2f09e9ae53971e886b78deacc9 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/E0600.rs:12:5
    |
 LL |     !"a"; //~ ERROR E0600
-   |     ^^^^
+   |     ^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
index 345691352b407a7084cc0e38c890caad7712b1d6..69f11b4b7c08c33c74af00c7a73a05bd941ec0aa 100644 (file)
@@ -17,6 +17,8 @@ LL |     x += 2;
    |     -^^^^^
    |     |
    |     cannot use `+=` on type `&str`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
 
 error[E0599]: no method named `z` found for type `&str` in the current scope
   --> $DIR/error-festival.rs:26:7
@@ -28,7 +30,9 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
   --> $DIR/error-festival.rs:29:5
    |
 LL |     !Question::Yes;
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ cannot apply unary operator `!`
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `Question`
 
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:35:5
diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.rs b/src/test/ui/feature-gate-macro-lifetime-matcher.rs
deleted file mode 100644 (file)
index 0d107d2..0000000
+++ /dev/null
@@ -1,19 +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.
-
-// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher
-// feature gate is not used.
-
-macro_rules! m { ($lt:lifetime) => {} }
-//~^ ERROR :lifetime fragment specifier is experimental and subject to change
-
-fn main() {
-    m!('a);
-}
diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.stderr b/src/test/ui/feature-gate-macro-lifetime-matcher.stderr
deleted file mode 100644 (file)
index b7805f6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: :lifetime fragment specifier is experimental and subject to change (see issue #46895)
-  --> $DIR/feature-gate-macro-lifetime-matcher.rs:14:19
-   |
-LL | macro_rules! m { ($lt:lifetime) => {} }
-   |                   ^^^^^^^^^^^^
-   |
-   = help: add #![feature(macro_lifetime_matcher)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gate-macro-literal-matcher.rs b/src/test/ui/feature-gate-macro-literal-matcher.rs
new file mode 100644 (file)
index 0000000..db5cca1
--- /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.
+
+// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher
+// feature gate is not used.
+
+macro_rules! m { ($lt:literal) => {} }
+//~^ ERROR :literal fragment specifier is experimental and subject to change
+
+fn main() {
+    m!("some string literal");
+}
diff --git a/src/test/ui/feature-gate-macro-literal-matcher.stderr b/src/test/ui/feature-gate-macro-literal-matcher.stderr
new file mode 100644 (file)
index 0000000..f714b91
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: :literal fragment specifier is experimental and subject to change (see issue #35625)
+  --> $DIR/feature-gate-macro-literal-matcher.rs:14:19
+   |
+LL | macro_rules! m { ($lt:literal) => {} }
+   |                   ^^^^^^^^^^^
+   |
+   = help: add #![feature(macro_literal_matcher)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index 1025b56f55bc3cfc7dc505f6d845a09f452a3a2a..85e9b56e4af9db3f0caeee55d1621e7421599e08 100644 (file)
@@ -2,13 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/feature-gate-negate-unsigned.rs:20:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^
+   |                       ^^ cannot apply unary operator `-`
+   |
+   = note: unsigned values cannot be negated
 
 error[E0600]: cannot apply unary operator `-` to type `u8`
   --> $DIR/feature-gate-negate-unsigned.rs:24:14
    |
 LL |     let _y = -x;
-   |              ^^
+   |              ^^ cannot apply unary operator `-`
+   |
+   = note: unsigned values cannot be negated
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gate-trivial_bounds-lint.rs b/src/test/ui/feature-gate-trivial_bounds-lint.rs
new file mode 100644 (file)
index 0000000..2d2d491
--- /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.
+
+// run-pass
+
+#![allow(unused)]
+#![deny(trivial_bounds)] // Ignored without the trivial_bounds feature flag.
+
+struct A where i32: Copy;
+
+fn main() {}
diff --git a/src/test/ui/feature-gate-trivial_bounds.rs b/src/test/ui/feature-gate-trivial_bounds.rs
new file mode 100644 (file)
index 0000000..ecc6896
--- /dev/null
@@ -0,0 +1,78 @@
+// 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(unused)]
+#![allow(type_alias_bounds)]
+
+pub trait Foo {
+    fn test(&self);
+}
+
+fn generic_function<X: Foo>(x: X) {}
+
+enum E where i32: Foo { V } //~ ERROR
+
+struct S where i32: Foo; //~ ERROR
+
+trait T where i32: Foo {} //~ ERROR
+
+union U where i32: Foo { f: i32 } //~ ERROR
+
+type Y where i32: Foo = (); // OK - bound is ignored
+
+impl Foo for () where i32: Foo { //~ ERROR
+    fn test(&self) {
+        3i32.test();
+        Foo::test(&4i32);
+        generic_function(5i32);
+    }
+}
+
+fn f() where i32: Foo //~ ERROR
+{
+    let s = S;
+    3i32.test();
+    Foo::test(&4i32);
+    generic_function(5i32);
+}
+
+fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
+    -s
+}
+
+fn use_for() where i32: Iterator { //~ ERROR
+    for _ in 2i32 {}
+}
+
+trait A {}
+
+impl A for i32 {}
+
+struct Dst<X: ?Sized> {
+    x: X,
+}
+
+struct TwoStrs(str, str) where str: Sized; //~ ERROR
+
+fn unsized_local() where Dst<A>: Sized { //~ ERROR
+    let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+}
+
+fn return_str() -> str where str: Sized { //~ ERROR
+    *"Sized".to_string().into_boxed_str()
+}
+
+// This is currently accepted because the function pointer isn't
+// considered global.
+fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
+    x.test();
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr
new file mode 100644 (file)
index 0000000..0794e86
--- /dev/null
@@ -0,0 +1,127 @@
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:20:1
+   |
+LL | enum E where i32: Foo { V } //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:22:1
+   |
+LL | struct S where i32: Foo; //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:24:1
+   |
+LL | trait T where i32: Foo {} //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:26:1
+   |
+LL | union U where i32: Foo { f: i32 } //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:30:1
+   |
+LL | / impl Foo for () where i32: Foo { //~ ERROR
+LL | |     fn test(&self) {
+LL | |         3i32.test();
+LL | |         Foo::test(&4i32);
+LL | |         generic_function(5i32);
+LL | |     }
+LL | | }
+   | |_^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:38:1
+   |
+LL | / fn f() where i32: Foo //~ ERROR
+LL | | {
+LL | |     let s = S;
+LL | |     3i32.test();
+LL | |     Foo::test(&4i32);
+LL | |     generic_function(5i32);
+LL | | }
+   | |_^ the trait `Foo` is not implemented for `i32`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:46:1
+   |
+LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
+LL | |     -s
+LL | | }
+   | |_^ the trait `std::ops::Neg` is not implemented for `std::string::String`
+   |
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:50:1
+   |
+LL | / fn use_for() where i32: Iterator { //~ ERROR
+LL | |     for _ in 2i32 {}
+LL | | }
+   | |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i32`
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:62:1
+   |
+LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst<A + 'static>`
+  --> $DIR/feature-gate-trivial_bounds.rs:64:1
+   |
+LL | / fn unsized_local() where Dst<A>: Sized { //~ ERROR
+LL | |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+LL | | }
+   | |_^ `A + 'static` does not have a constant size known at compile-time
+   |
+   = help: within `Dst<A + 'static>`, the trait `std::marker::Sized` is not implemented for `A + 'static`
+   = note: required because it appears within the type `Dst<A + 'static>`
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/feature-gate-trivial_bounds.rs:68:1
+   |
+LL | / fn return_str() -> str where str: Sized { //~ ERROR
+LL | |     *"Sized".to_string().into_boxed_str()
+LL | | }
+   | |_^ `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = help: see issue #48214
+   = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs
deleted file mode 100644 (file)
index 005f1f0..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-// FIXME(#44752) -- this scenario should not be warned
-fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-    22
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr
deleted file mode 100644 (file)
index 38d0536..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-2.rs:12:10
-   |
-LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-2.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs
deleted file mode 100644 (file)
index 263548c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32 // no warning!
-}
-
-// Once #44524 is fixed, this should issue a warning.
-impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-    fn method() { }
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr
deleted file mode 100644 (file)
index 49c06aa..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-3.rs:11:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-3.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'y` only used once
-  --> $DIR/single_use_lifetimes-3.rs:16:6
-   |
-LL | impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-   |      ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs
deleted file mode 100644 (file)
index 4ac8f8c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
- // Neither should issue a warning, as explicit lifetimes are mandatory in this case
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32
-}
-
-enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-    Variant(&'x u32)
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr
deleted file mode 100644 (file)
index 2df370f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:12:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-4.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:16:10
-   |
-LL | enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs
deleted file mode 100644 (file)
index cef904c..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-// Should not issue a warning, as explicit lifetimes are mandatory in this case:
-trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    fn foo(&self, arg: &'x u32);
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr
deleted file mode 100644 (file)
index eec426e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-5.rs:12:11
-   |
-LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |           ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-5.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs
deleted file mode 100644 (file)
index a97056b..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-
-fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-    *v
-}
-
-fn main() {}
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr
deleted file mode 100644 (file)
index 15917d3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes.rs:12:10
-   |
-LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
index 05c1f2aae8141bc0b7356e1362fa88d1ae56aa77..fe3e294d9e32ad24112df7ce06fad8b75e9be7e5 100644 (file)
@@ -5,7 +5,7 @@ LL | enum Bar {
    | ^^^^^^^^ recursive type has infinite size
 ...
 LL |     BarSome(Bar)
-   |             ---- recursive without indirection
+   |             --- recursive without indirection
    |
    = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
 
index 1aa99c402ed8dd826543612d3542ceb315f4aee0..b7e359af64ad06ea0c0f78ffc4e7f9e0c204b186 100644 (file)
@@ -4,7 +4,7 @@ error[E0072]: recursive type `Expr` has infinite size
 LL | enum Expr { //~ ERROR E0072
    | ^^^^^^^^^ recursive type has infinite size
 LL |     Plus(Expr, Expr),
-   |          ----- ----- recursive without indirection
+   |          ----  ---- recursive without indirection
    |          |
    |          recursive without indirection
    |
index 05c87fe66ee8508af42102db4c8c1b272a4cc243..937266d6d55735ef09906485dbb5bd3723bf9163 100644 (file)
@@ -6,6 +6,8 @@ LL | #[derive(Clone)] //~ ERROR conflicting implementations of trait `std::clone
 ...
 LL | impl<T: Clone + ?Sized> Clone for Node<[T]> {
    | ------------------------------------------- first implementation here
+   |
+   = note: upstream crates may add new impl of trait `std::clone::Clone` for type `[_]` in future versions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-50480.rs b/src/test/ui/issue-50480.rs
new file mode 100644 (file)
index 0000000..3427cf6
--- /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.
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/issue-50480.stderr b/src/test/ui/issue-50480.stderr
new file mode 100644 (file)
index 0000000..f5281fe
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:13:12
+   |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |            ^^^^^^^^^^ not found in this scope
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+  --> $DIR/issue-50480.rs:13:24
+   |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i32`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/issue-50480.rs:11:17
+   |
+LL | #[derive(Clone, Copy)]
+   |                 ^^^^
+LL | //~^ ERROR the trait `Copy` may not be implemented for this type
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                                                 --------  ------ this field does not implement `Copy`
+   |                                                 |
+   |                                                 this field does not implement `Copy`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0204, E0277, E0412.
+For more information about an error, try `rustc --explain E0204`.
diff --git a/src/test/ui/issue-50618.rs b/src/test/ui/issue-50618.rs
new file mode 100644 (file)
index 0000000..ed427c2
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+struct Point {
+    pub x: u64,
+    pub y: u64,
+}
+
+const TEMPLATE: Point = Point {
+    x: 0,
+    y: 0
+};
+
+fn main() {
+    let _ = || {
+        Point {
+            nonexistent: 0,
+            //~^ ERROR struct `Point` has no field named `nonexistent`
+            ..TEMPLATE
+        }
+    };
+}
diff --git a/src/test/ui/issue-50618.stderr b/src/test/ui/issue-50618.stderr
new file mode 100644 (file)
index 0000000..07cc5a1
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0560]: struct `Point` has no field named `nonexistent`
+  --> $DIR/issue-50618.rs:24:13
+   |
+LL |             nonexistent: 0,
+   |             ^^^^^^^^^^^ `Point` does not have this field
+   |
+   = note: available fields are: `x`, `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0560`.
index 2f9204e72d3fb0e73ac3e673ca3c945c3ef1f012..7ae01fb7d6012996c1e80ebb82038431117b6aaa 100644 (file)
@@ -5,6 +5,8 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              -^^^^^
    |                              |
    |                              cannot use `+=` on type `&isize`
+   |
+   = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
 
 error: aborting due to previous error
 
index 6994a377a06d7c01373dca5bc51034f61bbec92d..100fb6d3533f5961f0da0136a2ead6f0236cd479 100644 (file)
@@ -35,6 +35,10 @@ fn main() {
         endless_and_singing: true
     };
 
+    let mut mut_unused_var = 1;
+
+    let (mut var, unused_var) = (1, 2);
+
     if let SoulHistory { corridors_of_light,
                          mut hours_are_suns,
                          endless_and_singing: true } = who_from_the_womb_remembered {
index 7bfe2c9162ed17d9a30936a164989645d8bea17f..992be2c0a28445f28b98a3ac6b7159dabc5d9e02 100644 (file)
@@ -11,22 +11,40 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    |         ^^^^^^
    = note: #[warn(unused_variables)] implied by #[warn(unused)]
 
+warning: unused variable: `mut_unused_var`
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:13
+   |
+LL |     let mut mut_unused_var = 1;
+   |             ^^^^^^^^^^^^^^ help: consider using `_mut_unused_var` instead
+
+warning: unused variable: `var`
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:14
+   |
+LL |     let (mut var, unused_var) = (1, 2);
+   |              ^^^ help: consider using `_var` instead
+
+warning: unused variable: `unused_var`
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:19
+   |
+LL |     let (mut var, unused_var) = (1, 2);
+   |                   ^^^^^^^^^^ help: consider using `_unused_var` instead
+
 warning: unused variable: `corridors_of_light`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:26
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:42:26
    |
 LL |     if let SoulHistory { corridors_of_light,
    |                          ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
 
 warning: variable `hours_are_suns` is assigned to, but never used
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:39:26
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:30
    |
 LL |                          mut hours_are_suns,
-   |                          ^^^^^^^^^^^^^^^^^^
+   |                              ^^^^^^^^^^^^^^
    |
    = note: consider using `_hours_are_suns` instead
 
 warning: value assigned to `hours_are_suns` is never read
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:41:9
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:9
    |
 LL |         hours_are_suns = false;
    |         ^^^^^^^^^^^^^^
@@ -39,38 +57,61 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    = note: #[warn(unused_assignments)] implied by #[warn(unused)]
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:23
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:23
    |
 LL |         Large::Suit { case } => {}
    |                       ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:55:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:59:24
    |
 LL |         &Large::Suit { case } => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:60:27
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:64:27
    |
 LL |         box Large::Suit { case } => {}
    |                           ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:65:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:69:24
    |
 LL |         (Large::Suit { case },) => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:70:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:74:24
    |
 LL |         [Large::Suit { case }] => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:75:29
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:79:29
    |
 LL |         Tuple(Large::Suit { case }, ()) => {}
    |                             ^^^^ help: try ignoring the field: `case: _`
 
+warning: variable does not need to be mutable
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:9
+   |
+LL |     let mut mut_unused_var = 1;
+   |         ----^^^^^^^^^^^^^^
+   |         |
+   |         help: remove this `mut`
+   |
+note: lint level defined here
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9
+   |
+LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
+   |         ^^^^^^
+   = note: #[warn(unused_mut)] implied by #[warn(unused)]
+
+warning: variable does not need to be mutable
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:10
+   |
+LL |     let (mut var, unused_var) = (1, 2);
+   |          ----^^^
+   |          |
+   |          help: remove this `mut`
+
index f5e6b4d3b48622d2a30b591490f41c3407a6ea07..0a1926f8ae56a11dd9ad7f91881d37c3827cbbde 100644 (file)
@@ -24,6 +24,7 @@
 mod private_mod {
     // non-leaked `pub` items in private module should be linted
     pub use std::fmt;
+    pub use std::env::{Args}; // braced-use has different item spans than unbraced
 
     pub struct Hydrogen {
         // `pub` struct fields, too
index d1711be456bcc1667babc691e12d6ea7e376a4ed..2948deb23009c64b62b33b56fa7a380974aae3b3 100644 (file)
@@ -14,7 +14,15 @@ LL | #![warn(unreachable_pub)]
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:28:5
+  --> $DIR/unreachable_pub-pub_crate.rs:27:24
+   |
+LL |     pub use std::env::{Args}; // braced-use has different item spans than unbraced
+   |                        ^^^^ help: consider restricting its visibility: `pub(crate)`
+   |
+   = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+  --> $DIR/unreachable_pub-pub_crate.rs:29:5
    |
 LL |     pub struct Hydrogen {
    |     ---^^^^^^^^^^^^^^^^
@@ -24,7 +32,7 @@ LL |     pub struct Hydrogen {
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` field
-  --> $DIR/unreachable_pub-pub_crate.rs:30:9
+  --> $DIR/unreachable_pub-pub_crate.rs:31:9
    |
 LL |         pub neutrons: usize,
    |         ---^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |         pub neutrons: usize,
    |         help: consider restricting its visibility: `pub(crate)`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:36:9
+  --> $DIR/unreachable_pub-pub_crate.rs:37:9
    |
 LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `pub(crate)`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:40:5
+  --> $DIR/unreachable_pub-pub_crate.rs:41:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -50,7 +58,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:41:5
+  --> $DIR/unreachable_pub-pub_crate.rs:42:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -60,7 +68,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:42:5
+  --> $DIR/unreachable_pub-pub_crate.rs:43:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -70,7 +78,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:43:5
+  --> $DIR/unreachable_pub-pub_crate.rs:44:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -80,7 +88,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:44:5
+  --> $DIR/unreachable_pub-pub_crate.rs:45:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +98,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:45:5
+  --> $DIR/unreachable_pub-pub_crate.rs:46:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +108,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:46:5
+  --> $DIR/unreachable_pub-pub_crate.rs:47:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +118,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:49:47
+  --> $DIR/unreachable_pub-pub_crate.rs:50:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               -----------^^^^^^^^^^^^^
@@ -123,7 +131,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:54:9
+  --> $DIR/unreachable_pub-pub_crate.rs:55:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
index 347579c3e7bb93df13e9d262e7d6561241d1e9a1..5bb67670d85c2ae6f9bcfa708e28c944ed82f2c4 100644 (file)
@@ -19,6 +19,7 @@
 mod private_mod {
     // non-leaked `pub` items in private module should be linted
     pub use std::fmt;
+    pub use std::env::{Args}; // braced-use has different item spans than unbraced
 
     pub struct Hydrogen {
         // `pub` struct fields, too
index 1d693161108db03fe6d319e84de76c90d3c94d6e..ad88c55d54013a92c97697454bdfcfcac7ef4fb4 100644 (file)
@@ -14,7 +14,15 @@ LL | #![warn(unreachable_pub)]
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:23:5
+  --> $DIR/unreachable_pub.rs:22:24
+   |
+LL |     pub use std::env::{Args}; // braced-use has different item spans than unbraced
+   |                        ^^^^ help: consider restricting its visibility: `crate`
+   |
+   = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+  --> $DIR/unreachable_pub.rs:24:5
    |
 LL |     pub struct Hydrogen {
    |     ---^^^^^^^^^^^^^^^^
@@ -24,7 +32,7 @@ LL |     pub struct Hydrogen {
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` field
-  --> $DIR/unreachable_pub.rs:25:9
+  --> $DIR/unreachable_pub.rs:26:9
    |
 LL |         pub neutrons: usize,
    |         ---^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |         pub neutrons: usize,
    |         help: consider restricting its visibility: `crate`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:31:9
+  --> $DIR/unreachable_pub.rs:32:9
    |
 LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `crate`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:35:5
+  --> $DIR/unreachable_pub.rs:36:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -50,7 +58,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:36:5
+  --> $DIR/unreachable_pub.rs:37:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -60,7 +68,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:37:5
+  --> $DIR/unreachable_pub.rs:38:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -70,7 +78,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:38:5
+  --> $DIR/unreachable_pub.rs:39:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -80,7 +88,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:39:5
+  --> $DIR/unreachable_pub.rs:40:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +98,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:40:5
+  --> $DIR/unreachable_pub.rs:41:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +108,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:41:5
+  --> $DIR/unreachable_pub.rs:42:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +118,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:44:47
+  --> $DIR/unreachable_pub.rs:45:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               -----------^^^^^^^^^^^^^
@@ -123,7 +131,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:49:9
+  --> $DIR/unreachable_pub.rs:50:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
index bdb0e4a5c4044a821a96bd5826c8318396e4251d..765621f51d4fdbba999cb93c6f71e1171a8d065b 100644 (file)
@@ -4,7 +4,7 @@ error: invalid fragment specifier `foo`
 LL |     ($x:foo) => ()
    |      ^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
 
 error: aborting due to previous error
 
index 4dcb8afa94eab1564814c08140ac6b5855373477..54d280a63e7984637b095d8b3aafe0b024d2040e 100644 (file)
@@ -11,7 +11,7 @@
 // Check that we are refusing to match on complex nonterminals for which tokens are
 // unavailable and we'd have to go through AST comparisons.
 
-#![feature(decl_macro, macro_lifetime_matcher)]
+#![feature(decl_macro)]
 
 macro simple_nonterminal($nt_ident: ident, $nt_lifetime: lifetime, $nt_tt: tt) {
     macro n(a $nt_ident b $nt_lifetime c $nt_tt d) {
index e7483dbd3b546ca1afe1c5a89dcc1c8c734925da..7ef155e5f2ebece26ddc962389863f4f1bc7d023 100644 (file)
@@ -28,7 +28,7 @@ trait BadAnnotation1
 {}
 
 #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
-//~^ ERROR there is no type parameter C on trait BadAnnotation2
+//~^ ERROR there is no parameter C on trait BadAnnotation2
 trait BadAnnotation2<A,B>
 {}
 
index c37383757384e4ed2797d50735cf5c068b460762..1c5d4d603afc662d6cae88914ec8a29104a74eb9 100644 (file)
@@ -6,7 +6,7 @@ LL | #[rustc_on_unimplemented] //~ ERROR `#[rustc_on_unimplemented]` requires a
    |
    = note: eg `#[rustc_on_unimplemented = "foo"]`
 
-error[E0230]: there is no type parameter C on trait BadAnnotation2
+error[E0230]: there is no parameter C on trait BadAnnotation2
   --> $DIR/bad-annotation.rs:30:1
    |
 LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
index 165eccd42396b2e8310ffcc4b6d6a734d44363ec..b889c884fcbb223f66e2eb574dc482cf6c06f908 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!`
   --> $DIR/expr_unary.rs:17:16
    |
 LL |     let x: ! = ! { return; }; //~ ERROR unreachable
-   |                ^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: unreachable expression
   --> $DIR/expr_unary.rs:17:16
index 7d0427adb9f3e016b97aacdea78524ff14aff984..5071465b5f647569c5c5e754601658179bb411fe 100644 (file)
@@ -20,14 +20,14 @@ enum Foo<'a, T> {
 
 // Type U needs to outlive lifetime 'b
 struct Bar<'b, U> {
-    field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+    field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
 }
 
 
 
 // Type K needs to outlive lifetime 'c.
 enum Ying<'c, K> {
-    One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+    One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
 }
 
 struct Yang<V> {
index e6eaf9b47545037b024c681de9bda55a3fe2753e..604dd0b43c04a775346316858a92a415f0fbd987 100644 (file)
@@ -3,13 +3,13 @@ error[E0309]: the parameter type `U` may not live long enough
    |
 LL | struct Bar<'b, U> {
    |                - help: consider adding an explicit lifetime bound `U: 'b`...
-LL |     field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+LL |     field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
    |     ^^^^^^^^^^^^^
    |
 note: ...so that the reference type `&'b U` does not outlive the data it points at
   --> $DIR/enum.rs:23:5
    |
-LL |     field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+LL |     field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
    |     ^^^^^^^^^^^^^
 
 error[E0309]: the parameter type `K` may not live long enough
@@ -17,14 +17,14 @@ error[E0309]: the parameter type `K` may not live long enough
    |
 LL | enum Ying<'c, K> {
    |               - help: consider adding an explicit lifetime bound `K: 'c`...
-LL |     One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
-   |         ^^^^^^^^^^^^
+LL |     One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
+   |         ^^^^^^^^^^^
    |
 note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
   --> $DIR/enum.rs:30:9
    |
-LL |     One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
-   |         ^^^^^^^^^^^^
+LL |     One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
+   |         ^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs
new file mode 100644 (file)
index 0000000..e71166e
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
+//follow-up PR
+
+// A Collection trait and collection families. Based on
+// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
+// associated-type-constructors-part-2-family-traits/
+
+trait Collection<T> {
+    type Iter<'iter>: Iterator<Item=&'iter T>;
+    type Family: CollectionFamily;
+    // Test associated type defaults with parameters
+    type Sibling<U>: Collection<U> =
+        <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+    //~^ ERROR type parameters are not allowed on this type [E0109]
+
+    fn empty() -> Self;
+
+    fn add(&mut self, value: T);
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+}
+
+trait CollectionFamily {
+    type Member<T>: Collection<T, Family = Self>;
+}
+
+struct VecFamily;
+
+impl CollectionFamily for VecFamily {
+    type Member<T> = Vec<T>;
+}
+
+impl<T> Collection<T> for Vec<T> {
+    type Iter<'iter> = std::slice::Iter<'iter, T>;
+    type Family = VecFamily;
+
+    fn empty() -> Self {
+        Vec::new()
+    }
+
+    fn add(&mut self, value: T) {
+        self.push(value)
+    }
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+        self.iter()
+    }
+}
+
+fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
+//~^ ERROR type parameters are not allowed on this type [E0109]
+where
+    C: Collection<i32>,
+{
+    let mut res = C::Family::Member::<f32>::empty();
+    for &v in ints.iterate() {
+        res.add(v as f32);
+    }
+    res
+}
+
+fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+//~^ ERROR type parameters are not allowed on this type [E0109]
+where
+    C: Collection<i32>,
+{
+    let mut res = C::Family::Member::<f32>::empty();
+    for &v in ints.iterate() {
+        res.add(v as f32);
+    }
+    res
+}
+
+fn use_floatify() {
+    let a = vec![1i32, 2, 3];
+    let b = floatify(a);
+    println!("{}", b.iterate().next());
+    let c = floatify_sibling(a);
+    println!("{}", c.iterate().next());
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr
new file mode 100644 (file)
index 0000000..ed96570
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0109]: type parameters are not allowed on this type
+  --> $DIR/collections.rs:65:90
+   |
+LL | fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
+   |                                                                                          ^^^ type parameter not allowed
+
+error[E0109]: type parameters are not allowed on this type
+  --> $DIR/collections.rs:77:69
+   |
+LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+   |                                                                     ^^^ type parameter not allowed
+
+error[E0109]: type parameters are not allowed on this type
+  --> $DIR/collections.rs:26:71
+   |
+LL |         <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+   |                                                                       ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/collections.rs:33:50
+   |
+LL |     fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+   |                                                  ^^^^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/collections.rs:59:50
+   |
+LL |     fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+   |                                                  ^^^^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
+
+Some errors occurred: E0109, E0110.
+For more information about an error, try `rustc --explain E0109`.
index 0d9b487876e211d57c2add25c1a311522e6fd5d0..04294100315264ec5f1a26bb3a6834da7e86500b 100644 (file)
@@ -10,6 +10,8 @@
 
 #![feature(generic_associated_types)]
 
+use std::ops::Deref;
+
 //FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
 //follow-up PR
 
@@ -18,11 +20,18 @@ trait Foo {
 }
 
 trait Baz {
-    type Quux<'a>;
+    type Quux<'a>: Foo;
+
+    // This weird type tests that we can use universal function call syntax to access the Item on
+    type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+    //~| ERROR lifetime parameters are not allowed on this type [E0110]
 }
 
 impl<T> Baz for T where T: Foo {
-    type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
+    type Quux<'a> = T;
+
+    type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
     //~^ ERROR lifetime parameters are not allowed on this type [E0110]
 }
 
index 054530e24bd1836ee79467f90e9ad60f1c1c8f9e..764a0db2478a8478d7d86dd03758905bf9db48f4 100644 (file)
@@ -1,9 +1,21 @@
 error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/construct_with_other_type.rs:25:37
+  --> $DIR/construct_with_other_type.rs:26:46
    |
-LL |     type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
-   |                                     ^^ lifetime parameter not allowed on this type
+LL |     type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+   |                                              ^^ lifetime parameter not allowed on this type
 
-error: aborting due to previous error
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/construct_with_other_type.rs:26:63
+   |
+LL |     type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+   |                                                               ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/construct_with_other_type.rs:34:40
+   |
+LL |     type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
+   |                                        ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0110`.
index 1287ddaf7f7feb3f722b1896a88042f2ef856904..38967dbbe4530ea4ab28da1943889f4ef1e8d54f 100644 (file)
@@ -20,13 +20,40 @@ trait Iterable {
     type Iter<'a>: Iterator<Item = Self::Item<'a>>;
     //~^ ERROR lifetime parameters are not allowed on this type [E0110]
 
-    // This weird type tests that we can use universal function call syntax to access the Item on
-    // Self::Iter which we have declared to be an Iterator
-    type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
+    fn iter<'a>(&'a self) -> Self::Iter<'a>;
     //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+}
 
-    fn iter<'a>(&'a self) -> Self::Iter<'a>;
+// Impl for struct type
+impl<T> Iterable for Vec<T> {
+    type Item<'a> = &'a T;
+    type Iter<'a> = std::slice::Iter<'a, T>;
+
+    fn iter<'a>(&'a self) -> Self::Iter<'a> {
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+        self.iter()
+    }
+}
+
+// Impl for a primitive type
+impl<T> Iterable for [T] {
+    type Item<'a> = &'a T;
+    type Iter<'a> = std::slice::Iter<'a, T>;
+
+    fn iter<'a>(&'a self) -> Self::Iter<'a> {
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+        self.iter()
+    }
+}
+
+fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+    it.iter()
+}
+
+fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
     //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+    it.iter().next()
 }
 
 fn main() {}
index d33eebb42d6079326cc124ac0cb22d004167c658..0e251300e451f8bb49eae67a15577a72ead73977 100644 (file)
@@ -5,17 +5,35 @@ LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>>;
    |                                               ^^ lifetime parameter not allowed on this type
 
 error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/iterable.rs:25:48
+  --> $DIR/iterable.rs:49:53
    |
-LL |     type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
-   |                                                ^^ lifetime parameter not allowed on this type
+LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+   |                                                     ^^ lifetime parameter not allowed on this type
 
 error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/iterable.rs:28:41
+  --> $DIR/iterable.rs:54:60
+   |
+LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
+   |                                                            ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/iterable.rs:23:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'a>;
    |                                         ^^ lifetime parameter not allowed on this type
 
-error: aborting due to 3 previous errors
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/iterable.rs:32:41
+   |
+LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
+   |                                         ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/iterable.rs:43:41
+   |
+LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
+   |                                         ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0110`.
diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs
new file mode 100644 (file)
index 0000000..51527d4
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
+//follow-up PR
+
+//FIXME(#44265): Update expected errors once E110 is resolved, now does not get past `trait Foo`
+
+trait Foo {
+    type A<'a>;
+    type B<'a, 'b>;
+    type C;
+    type D<T>;
+    type E<'a, T>;
+    // Test parameters in default values
+    type FOk<T> = Self::E<'static, T>;
+    //~^ ERROR type parameters are not allowed on this type [E0109]
+    //~| ERROR lifetime parameters are not allowed on this type [E0110]
+    type FErr1 = Self::E<'static, 'static>; // Error
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+    type FErr2<T> = Self::E<'static, T, u32>; // Error
+    //~^ ERROR type parameters are not allowed on this type [E0109]
+    //~| ERROR lifetime parameters are not allowed on this type [E0110]
+}
+
+struct Fooy;
+
+impl Foo for Fooy {
+    type A = u32; // Error: parameter expected
+    type B<'a, T> = Vec<T>; // Error: lifetime param expected
+    type C<'a> = u32; // Error: no param expected
+    type D<'a> = u32; // Error: type param expected
+    type E<T, U> = u32; // Error: lifetime expected as the first param
+}
+
+struct Fooer;
+
+impl Foo for Fooer {
+    type A<T> = u32; // Error: lifetime parameter expected
+    type B<'a> = u32; // Error: another lifetime param expected
+    type C<T> = T; // Error: no param expected
+    type D<'b, T> = u32; // Error: unexpected lifetime param
+    type E<'a, 'b> = u32; // Error: type expected as the second param
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr
new file mode 100644 (file)
index 0000000..df83fda
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0109]: type parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:26:36
+   |
+LL |     type FOk<T> = Self::E<'static, T>;
+   |                                    ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:26:27
+   |
+LL |     type FOk<T> = Self::E<'static, T>;
+   |                           ^^^^^^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:29:26
+   |
+LL |     type FErr1 = Self::E<'static, 'static>; // Error
+   |                          ^^^^^^^ lifetime parameter not allowed on this type
+
+error[E0109]: type parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:31:38
+   |
+LL |     type FErr2<T> = Self::E<'static, T, u32>; // Error
+   |                                      ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:31:29
+   |
+LL |     type FErr2<T> = Self::E<'static, T, u32>; // Error
+   |                             ^^^^^^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
+
+Some errors occurred: E0109, E0110.
+For more information about an error, try `rustc --explain E0109`.
diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs
new file mode 100644 (file)
index 0000000..6cdcaf2
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+
+//FIXME(#44265): The lifetime shadowing and type parameter shadowing
+// should cause an error. Now it compiles (errorneously) and this will be addressed
+// by a future PR. Then remove the following:
+// compile-pass
+
+trait Shadow<'a> {
+    type Bar<'a>; // Error: shadowed lifetime
+}
+
+trait NoShadow<'a> {
+    type Bar<'b>; // OK
+}
+
+impl<'a> NoShadow<'a> for &'a u32 {
+    type Bar<'a> = i32; // Error: shadowed lifetime
+}
+
+trait ShadowT<T> {
+    type Bar<T>; // Error: shadowed type parameter
+}
+
+trait NoShadowT<T> {
+    type Bar<U>; // OK
+}
+
+impl<T> NoShadowT<T> for Option<T> {
+    type Bar<T> = i32; // Error: shadowed type parameter
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.stdout b/src/test/ui/rfc1598-generic-associated-types/shadowing.stdout
new file mode 100644 (file)
index 0000000..e69de29
index f9e270ee92e22999d832518d729288f9a66786d7..522ddb5dc135e36e162d34cc5bfb34e2f27f427b 100644 (file)
@@ -35,4 +35,48 @@ struct Foo<T: StreamingIterator> {
 fn foo<T>(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ }
 //~^ ERROR lifetime parameters are not allowed on this type [E0110]
 
+// Full example of enumerate iterator
+
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+struct StreamEnumerate<I> {
+    iter: I,
+    count: usize,
+}
+
+impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
+    type Item<'a> = (usize, I::Item<'a>);
+    //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+    fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
+        //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+        match self.iter.next() {
+            None => None,
+            Some(val) => {
+                let r = Some((self.count, val));
+                self.count += 1;
+                r
+            }
+        }
+    }
+}
+
+impl<I> StreamEnumerate<I> {
+    pub fn new(iter: I) -> Self {
+        StreamEnumerate {
+            count: 0,
+            iter: iter,
+        }
+    }
+}
+
+fn test_stream_enumerate() {
+    let v = vec!["a", "b", "c"];
+    let se = StreamEnumerate::new(v.iter());
+    let a: &str = se.next().unwrap().1;
+    for (i, s) in se {
+        println!("{} {}", i, s);
+    }
+    println!("{}", a);
+}
+
+
 fn main() {}
index 9ab80151a7ed319f2f99a3430de56038b823419f..607a4b8d57996e1cb0343783c379a9e4669093c8 100644 (file)
@@ -16,6 +16,18 @@ error[E0110]: lifetime parameters are not allowed on this type
 LL |     fn next<'a>(&'a self) -> Option<Self::Item<'a>>;
    |                                                ^^ lifetime parameter not allowed on this type
 
-error: aborting due to 3 previous errors
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/streaming_iterator.rs:47:37
+   |
+LL |     type Item<'a> = (usize, I::Item<'a>);
+   |                                     ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/streaming_iterator.rs:49:48
+   |
+LL |     fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
+   |                                                ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0110`.
diff --git a/src/test/ui/single-use-lifetime/fn-types.rs b/src/test/ui/single-use-lifetime/fn-types.rs
new file mode 100644 (file)
index 0000000..c5d98d2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+struct Foo {
+  a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+  b: for<'a> fn(&'a u32, &'a u32), // OK, used twice.
+  c: for<'a> fn(&'a u32) -> &'a u32, // OK, used twice.
+  d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+    //~^ ERROR return type references lifetime `'a`, which is not constrained by the fn input types
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/fn-types.stderr b/src/test/ui/single-use-lifetime/fn-types.stderr
new file mode 100644 (file)
index 0000000..bec712b
--- /dev/null
@@ -0,0 +1,21 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/fn-types.rs:19:10
+   |
+LL |   a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+   |          ^^
+   |
+note: lint level defined here
+  --> $DIR/fn-types.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+  --> $DIR/fn-types.rs:22:22
+   |
+LL |   d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+   |                      ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0581`.
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs
new file mode 100644 (file)
index 0000000..9001a8d
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &'a u32, y: &'b u32) {
+    //~^ ERROR `'a` only used once
+    //~| ERROR `'b` only used once
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
new file mode 100644 (file)
index 0000000..2011359
--- /dev/null
@@ -0,0 +1,20 @@
+error: lifetime parameter `'b` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |                      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |          ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
new file mode 100644 (file)
index 0000000..2a9e80d
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
new file mode 100644 (file)
index 0000000..e9a3570
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument.rs:18:6
+   |
+LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
new file mode 100644 (file)
index 0000000..d024094
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn when lifetime name is used only
+// once in a fn return type -- using `'_` is not legal there,
+// as it must refer back to an argument.
+//
+// (Normally, using `'static` would be preferred, but there are
+// times when that is not what you want.)
+//
+// run-pass
+
+fn b<'a>() -> &'a u32 { // OK: used only in return type
+    &22
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs
new file mode 100644 (file)
index 0000000..9cdad09
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an impl.
+//
+// (Actually, until #15872 is fixed, you can't use `'_` here, but
+// hopefully that will come soon.)
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a(&self) {
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr
new file mode 100644 (file)
index 0000000..1718f19
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-impl-header.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs
new file mode 100644 (file)
index 0000000..1ca078c
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr
new file mode 100644 (file)
index 0000000..38e90e7
--- /dev/null
@@ -0,0 +1,20 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:22:19
+   |
+LL |     fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+   |                   ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:21:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs
new file mode 100644 (file)
index 0000000..7d2ffa3
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn for a lifetime used just once in a return type,
+// where that return type is in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self) -> &'a u32 { // OK for 'a
+        &22
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr
new file mode 100644 (file)
index 0000000..32fd284
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-return.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-struct.rs b/src/test/ui/single-use-lifetime/one-use-in-struct.rs
new file mode 100644 (file)
index 0000000..5c758d9
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not warn for named lifetimes in structs,
+// even when they are only used once (since to not use a named
+// lifetime is illegal!)
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+enum Bar<'f> {
+    Data(&'f u32)
+}
+
+trait Baz<'f> { }
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs
new file mode 100644 (file)
index 0000000..99e9eaf
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+// Test that we DO warn for a lifetime on an impl used only in `&self`
+// in a trait method.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+        None
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr
new file mode 100644 (file)
index 0000000..e527867
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'g` only used once
+  --> $DIR/one-use-in-trait-method-argument.rs:25:13
+   |
+LL |     fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+   |             ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-trait-method-argument.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs
new file mode 100644 (file)
index 0000000..d210be4
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+// Test that we DO NOT warn when lifetime name is used in
+// both the argument and return.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice
+    &22
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs
new file mode 100644 (file)
index 0000000..f43a3e1
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used multiple
+// argments, or more than once in a single argument.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32, y: &'a u32) { // OK: used twice
+}
+
+fn d<'a>(x: (&'a u32, &'a u32)) { // OK: used twice
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs
new file mode 100644 (file)
index 0000000..d224d9f
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> {
+    fn inherent_a(&self, data: &'f u32) {
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs
new file mode 100644 (file)
index 0000000..7b69a6f
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl method and
+// header.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) -> &'a u32{
+      data
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr
new file mode 100644 (file)
index 0000000..6fc6661
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs b/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs
new file mode 100644 (file)
index 0000000..ffba3d8
--- /dev/null
@@ -0,0 +1,32 @@
+// 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.
+
+// Test that we DO NOT warn for a lifetime on an impl used in both
+// header and in an associated type.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-fn.rs b/src/test/ui/single-use-lifetime/zero-uses-in-fn.rs
new file mode 100644 (file)
index 0000000..b71b189
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn d<'a>() { } //~ ERROR `'a` never used
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr b/src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr
new file mode 100644 (file)
index 0000000..f1cdc6e
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` never used
+  --> $DIR/zero-uses-in-fn.rs:17:6
+   |
+LL | fn d<'a>() { } //~ ERROR `'a` never used
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/zero-uses-in-fn.rs:13:9
+   |
+LL | #![deny(unused_lifetime)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-impl.rs b/src/test/ui/single-use-lifetime/zero-uses-in-impl.rs
new file mode 100644 (file)
index 0000000..6a09727
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo { }
+
+impl<'a> Foo { } //~ ERROR `'a` never used
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr b/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr
new file mode 100644 (file)
index 0000000..d2dd26e
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` never used
+  --> $DIR/zero-uses-in-impl.rs:19:6
+   |
+LL | impl<'a> Foo { } //~ ERROR `'a` never used
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/zero-uses-in-impl.rs:13:9
+   |
+LL | #![deny(unused_lifetime)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 8be1af61d80b3a1959cdc46c28aa085082ae2e99..2949a22747b8781639bdeba48e205aeebeea74d8 100644 (file)
@@ -32,7 +32,7 @@ LL | #[derive(Copy)] //~ ERROR may not be implemented for this type
    |          ^^^^
 LL | enum EFoo2<'a> {
 LL |     Bar(&'a mut bool),
-   |         ------------- this field does not implement `Copy`
+   |         ------------ this field does not implement `Copy`
 
 error: aborting due to 4 previous errors
 
index 23315e3b76a4f9e73e47ef987c720d7b5c199cd9..e1e13e9256dcdb909adf83a5ac72f142e6d901c2 100644 (file)
@@ -5,6 +5,8 @@ LL |     let x: Option<_> = None;
    |         - consider giving `x` a type
 LL |     x.unwrap().method_that_could_exist_on_some_type();
    |     ^^^^^^^^^^ cannot infer type for `T`
+   |
+   = note: type must be known at this point
 
 error[E0282]: type annotations needed
   --> $DIR/issue-42234-unknown-receiver-type.rs:22:5
@@ -12,6 +14,8 @@ error[E0282]: type annotations needed
 LL | /     data.iter() //~ ERROR 22:5: 23:20: type annotations needed
 LL | |         .sum::<_>()
    | |___________________^ cannot infer type for `_`
+   |
+   = note: type must be known at this point
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/method-and-field-eager-resolution.rs b/src/test/ui/span/method-and-field-eager-resolution.rs
new file mode 100644 (file)
index 0000000..29011ab
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+// Test that spans get only base in eager type resolution (structurally_resolve_type).
+
+fn main() {
+    let mut x = Default::default();
+    x.0;
+    //~^ ERROR type annotations needed
+    x = 1;
+}
+
+fn foo() {
+    let mut x = Default::default();
+    x[0];
+    //~^ ERROR type annotations needed
+    x = 1;
+}
diff --git a/src/test/ui/span/method-and-field-eager-resolution.stderr b/src/test/ui/span/method-and-field-eager-resolution.stderr
new file mode 100644 (file)
index 0000000..21e1982
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0282]: type annotations needed
+  --> $DIR/method-and-field-eager-resolution.rs:15:5
+   |
+LL |     let mut x = Default::default();
+   |         ----- consider giving `x` a type
+LL |     x.0;
+   |     ^ cannot infer type for `_`
+   |
+   = note: type must be known at this point
+
+error[E0282]: type annotations needed
+  --> $DIR/method-and-field-eager-resolution.rs:22:5
+   |
+LL |     let mut x = Default::default();
+   |         ----- consider giving `x` a type
+LL |     x[0];
+   |     ^ cannot infer type for `_`
+   |
+   = note: type must be known at this point
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs b/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs
new file mode 100644 (file)
index 0000000..4275e80
--- /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.
+
+// intentionally blank
diff --git a/src/test/ui/suggestions/removing-extern-crate.fixed b/src/test/ui/suggestions/removing-extern-crate.fixed
new file mode 100644 (file)
index 0000000..723137f
--- /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.
+
+// compile-flags: --edition 2018
+// aux-build:removing-extern-crate.rs
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_idioms)]
+#![allow(unused_imports)]
+
+use std as foo;
+
+
+mod another {
+    use std as foo;
+    use std;
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/removing-extern-crate.rs b/src/test/ui/suggestions/removing-extern-crate.rs
new file mode 100644 (file)
index 0000000..2947908
--- /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.
+
+// compile-flags: --edition 2018
+// aux-build:removing-extern-crate.rs
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_idioms)]
+#![allow(unused_imports)]
+
+extern crate std as foo;
+extern crate core;
+
+mod another {
+    extern crate std as foo;
+    extern crate std;
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/removing-extern-crate.stderr b/src/test/ui/suggestions/removing-extern-crate.stderr
new file mode 100644 (file)
index 0000000..317703d
--- /dev/null
@@ -0,0 +1,31 @@
+warning: `extern crate` is unnecessary in the new edition
+  --> $DIR/removing-extern-crate.rs:19:1
+   |
+LL | extern crate std as foo;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;`
+   |
+note: lint level defined here
+  --> $DIR/removing-extern-crate.rs:16:9
+   |
+LL | #![warn(rust_2018_idioms)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: #[warn(unnecessary_extern_crate)] implied by #[warn(rust_2018_idioms)]
+
+warning: `extern crate` is unnecessary in the new edition
+  --> $DIR/removing-extern-crate.rs:20:1
+   |
+LL | extern crate core;
+   | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+warning: `extern crate` is unnecessary in the new edition
+  --> $DIR/removing-extern-crate.rs:23:5
+   |
+LL |     extern crate std as foo;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;`
+
+warning: `extern crate` is unnecessary in the new edition
+  --> $DIR/removing-extern-crate.rs:24:5
+   |
+LL |     extern crate std;
+   |     ^^^^^^^^^^^^^^^^^ help: use `use`: `use std;`
+
diff --git a/src/test/ui/trivial-bounds-inconsistent-associated-functions.rs b/src/test/ui/trivial-bounds-inconsistent-associated-functions.rs
new file mode 100644 (file)
index 0000000..49c9df9
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+// run-pass
+// Inconsistent bounds with trait implementations
+
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait A {
+    fn foo(&self) -> Self where Self: Copy;
+}
+
+impl A for str {
+    fn foo(&self) -> Self where Self: Copy { *"" }
+}
+
+impl A for i32 {
+    fn foo(&self) -> Self { 3 }
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent-associated-functions.stderr b/src/test/ui/trivial-bounds-inconsistent-associated-functions.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr
new file mode 100644 (file)
index 0000000..6654786
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0596]: cannot borrow immutable item `**t` as mutable
+  --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
+   |
+LL |     *t //~ ERROR
+   |     ^^ cannot borrow as mutable
+   |
+   = note: the value which is causing this path not to be mutable is...: `*t`
+
+error[E0596]: cannot borrow immutable item `**t` as mutable
+  --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
+   |
+LL |     {*t} //~ ERROR
+   |      ^^ cannot borrow as mutable
+   |
+   = note: the value which is causing this path not to be mutable is...: `*t`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.rs b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.rs
new file mode 100644 (file)
index 0000000..2c4d9d8
--- /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.
+
+// Check that reborrows are still illegal with Copy mutable references
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+    *t //~ ERROR
+}
+
+fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+    {*t} //~ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.stderr b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.stderr
new file mode 100644 (file)
index 0000000..bea2bb6
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0389]: cannot borrow data mutably in a `&` reference
+  --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
+   |
+LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+   |                        --------------- use `&'a mut &'a mut i32` here to make mutable
+LL |     *t //~ ERROR
+   |     ^^ assignment into an immutable reference
+
+error[E0389]: cannot borrow data mutably in a `&` reference
+  --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
+   |
+LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+   |                             --------------- use `&'a mut &'a mut i32` here to make mutable
+LL |     {*t} //~ ERROR
+   |      ^^ assignment into an immutable reference
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0389`.
diff --git a/src/test/ui/trivial-bounds-inconsistent-copy.rs b/src/test/ui/trivial-bounds-inconsistent-copy.rs
new file mode 100644 (file)
index 0000000..375885a
--- /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.
+
+// run-pass
+// Check tautalogically false `Copy` bounds
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+fn copy_string(t: String) -> String where String: Copy {
+    is_copy(&t);
+    let x = t;
+    drop(t);
+    t
+}
+
+fn copy_out_string(t: &String) -> String where String: Copy {
+    *t
+}
+
+fn copy_string_with_param<T>(x: String) where String: Copy {
+    let y = x;
+    let z = x;
+}
+
+// Check that no reborrowing occurs
+fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
+    is_copy(t);
+    let x = *t;
+    drop(x);
+    x
+}
+
+fn is_copy<T: Copy>(t: &T) {}
+
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent-copy.stderr b/src/test/ui/trivial-bounds-inconsistent-copy.stderr
new file mode 100644 (file)
index 0000000..ae63900
--- /dev/null
@@ -0,0 +1,41 @@
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-copy.rs:16:1
+   |
+LL | / fn copy_string(t: String) -> String where String: Copy {
+LL | |     is_copy(&t);
+LL | |     let x = t;
+LL | |     drop(t);
+LL | |     t
+LL | | }
+   | |_^
+   |
+   = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-copy.rs:23:1
+   |
+LL | / fn copy_out_string(t: &String) -> String where String: Copy {
+LL | |     *t
+LL | | }
+   | |_^
+
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-copy.rs:27:1
+   |
+LL | / fn copy_string_with_param<T>(x: String) where String: Copy {
+LL | |     let y = x;
+LL | |     let z = x;
+LL | | }
+   | |_^
+
+warning: Trait bound for<'b> &'b mut i32: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-copy.rs:33:1
+   |
+LL | / fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
+LL | |     is_copy(t);
+LL | |     let x = *t;
+LL | |     drop(x);
+LL | |     x
+LL | | }
+   | |_^
+
diff --git a/src/test/ui/trivial-bounds-inconsistent-sized.rs b/src/test/ui/trivial-bounds-inconsistent-sized.rs
new file mode 100644 (file)
index 0000000..14ba11c
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+// run-pass
+// Check tautalogically false `Sized` bounds
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait A {}
+
+impl A for i32 {}
+
+struct T<X: ?Sized> {
+    x: X,
+}
+
+struct S(str, str) where str: Sized;
+
+fn unsized_local() where for<'a> T<A + 'a>: Sized {
+    let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
+}
+
+fn return_str() -> str where str: Sized {
+    *"Sized".to_string().into_boxed_str()
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent-sized.stderr b/src/test/ui/trivial-bounds-inconsistent-sized.stderr
new file mode 100644 (file)
index 0000000..ee2ff7d
--- /dev/null
@@ -0,0 +1,24 @@
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-sized.rs:24:1
+   |
+LL | struct S(str, str) where str: Sized;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound for<'a> T<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-sized.rs:26:1
+   |
+LL | / fn unsized_local() where for<'a> T<A + 'a>: Sized {
+LL | |     let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
+LL | | }
+   | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-sized.rs:30:1
+   |
+LL | / fn return_str() -> str where str: Sized {
+LL | |     *"Sized".to_string().into_boxed_str()
+LL | | }
+   | |_^
+
diff --git a/src/test/ui/trivial-bounds-inconsistent-well-formed.rs b/src/test/ui/trivial-bounds-inconsistent-well-formed.rs
new file mode 100644 (file)
index 0000000..5fcdbfc
--- /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.
+
+// run-pass
+// Test that inconsistent bounds are used in well-formedness checks
+#![feature(trivial_bounds)]
+
+use std::fmt::Debug;
+
+pub fn foo() where Vec<str>: Debug, str: Copy {
+    let x = vec![*"1"];
+    println!("{:?}", x);
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent-well-formed.stderr b/src/test/ui/trivial-bounds-inconsistent-well-formed.stderr
new file mode 100644 (file)
index 0000000..b51ecd4
--- /dev/null
@@ -0,0 +1,20 @@
+warning: Trait bound std::vec::Vec<str>: std::fmt::Debug does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
+   |
+LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
+LL | |     let x = vec![*"1"];
+LL | |     println!("{:?}", x);
+LL | | }
+   | |_^
+   |
+   = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound str: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
+   |
+LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
+LL | |     let x = vec![*"1"];
+LL | |     println!("{:?}", x);
+LL | | }
+   | |_^
+
diff --git a/src/test/ui/trivial-bounds-inconsistent.rs b/src/test/ui/trivial-bounds-inconsistent.rs
new file mode 100644 (file)
index 0000000..2c8b873
--- /dev/null
@@ -0,0 +1,81 @@
+// 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.
+
+// run-pass
+
+// Check that tautalogically false bounds are accepted, and are used
+// in type inference.
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+pub trait Foo {
+    fn test(&self);
+}
+
+fn generic_function<X: Foo>(x: X) {}
+
+enum E where i32: Foo { V }
+
+struct S where i32: Foo;
+
+trait T where i32: Foo {}
+
+union U where i32: Foo { f: i32 }
+
+type Y where i32: Foo = ();
+
+impl Foo for () where i32: Foo {
+    fn test(&self) {
+        3i32.test();
+        Foo::test(&4i32);
+        generic_function(5i32);
+    }
+}
+
+fn f() where i32: Foo {
+    let s = S;
+    3i32.test();
+    Foo::test(&4i32);
+    generic_function(5i32);
+}
+
+fn g() where &'static str: Foo {
+    "Foo".test();
+    Foo::test(&"Foo");
+    generic_function("Foo");
+}
+
+trait A {}
+
+impl A for i32 {}
+
+struct Dst<X: ?Sized> {
+    x: X,
+}
+
+struct TwoStrs(str, str) where str: Sized;
+
+fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
+    let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+}
+
+fn return_str() -> str where str: Sized {
+    *"Sized".to_string().into_boxed_str()
+}
+
+fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
+    -s
+}
+
+fn use_for() where i32: Iterator {
+    for _ in 2i32 {}
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-inconsistent.stderr b/src/test/ui/trivial-bounds-inconsistent.stderr
new file mode 100644 (file)
index 0000000..ee3c751
--- /dev/null
@@ -0,0 +1,112 @@
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:24:1
+   |
+LL | enum E where i32: Foo { V }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:26:1
+   |
+LL | struct S where i32: Foo;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:28:1
+   |
+LL | trait T where i32: Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:30:1
+   |
+LL | union U where i32: Foo { f: i32 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/trivial-bounds-inconsistent.rs:32:14
+   |
+LL | type Y where i32: Foo = ();
+   |              ^^^^^^^^
+   |
+   = note: #[warn(type_alias_bounds)] on by default
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:32:1
+   |
+LL | type Y where i32: Foo = ();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:34:1
+   |
+LL | / impl Foo for () where i32: Foo {
+LL | |     fn test(&self) {
+LL | |         3i32.test();
+LL | |         Foo::test(&4i32);
+LL | |         generic_function(5i32);
+LL | |     }
+LL | | }
+   | |_^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:42:1
+   |
+LL | / fn f() where i32: Foo {
+LL | |     let s = S;
+LL | |     3i32.test();
+LL | |     Foo::test(&4i32);
+LL | |     generic_function(5i32);
+LL | | }
+   | |_^
+
+warning: Trait bound &'static str: Foo does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:49:1
+   |
+LL | / fn g() where &'static str: Foo {
+LL | |     "Foo".test();
+LL | |     Foo::test(&"Foo");
+LL | |     generic_function("Foo");
+LL | | }
+   | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:63:1
+   |
+LL | struct TwoStrs(str, str) where str: Sized;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound for<'a> Dst<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:65:1
+   |
+LL | / fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
+LL | |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+LL | | }
+   | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:69:1
+   |
+LL | / fn return_str() -> str where str: Sized {
+LL | |     *"Sized".to_string().into_boxed_str()
+LL | | }
+   | |_^
+
+warning: Trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:73:1
+   |
+LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
+LL | |     -s
+LL | | }
+   | |_^
+
+warning: Trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-inconsistent.rs:77:1
+   |
+LL | / fn use_for() where i32: Iterator {
+LL | |     for _ in 2i32 {}
+LL | | }
+   | |_^
+
diff --git a/src/test/ui/trivial-bounds-leak-copy.rs b/src/test/ui/trivial-bounds-leak-copy.rs
new file mode 100644 (file)
index 0000000..9850ec2
--- /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.
+
+// Check that false Copy bounds don't leak
+#![feature(trivial_bounds)]
+
+fn copy_out_string(t: &String) -> String where String: Copy {
+    *t
+}
+
+fn move_out_string(t: &String) -> String {
+    *t //~ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-leak-copy.stderr b/src/test/ui/trivial-bounds-leak-copy.stderr
new file mode 100644 (file)
index 0000000..3c3fcbf
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/trivial-bounds-leak-copy.rs:19:5
+   |
+LL |     *t //~ ERROR
+   |     ^^ cannot move out of borrowed content
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/trivial-bounds-leak.rs b/src/test/ui/trivial-bounds-leak.rs
new file mode 100644 (file)
index 0000000..98cb5b2
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+// Check that false bounds don't leak
+#![feature(trivial_bounds)]
+
+pub trait Foo {
+    fn test(&self);
+}
+
+fn return_str() -> str where str: Sized {
+    *"Sized".to_string().into_boxed_str()
+}
+
+fn cant_return_str() -> str { //~ ERROR
+    *"Sized".to_string().into_boxed_str()
+}
+
+fn my_function() where i32: Foo
+{
+    3i32.test();
+    Foo::test(&4i32);
+    generic_function(5i32);
+}
+
+fn foo() {
+    3i32.test(); //~ ERROR
+    Foo::test(&4i32); //~ ERROR
+    generic_function(5i32); //~ ERROR
+}
+
+fn generic_function<T: Foo>(t: T) {}
+
+fn main() {}
+
diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr
new file mode 100644 (file)
index 0000000..df91ba0
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/trivial-bounds-leak.rs:22:25
+   |
+LL | fn cant_return_str() -> str { //~ ERROR
+   |                         ^^^ `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = note: the return type of a function must have a statically known size
+
+error[E0599]: no method named `test` found for type `i32` in the current scope
+  --> $DIR/trivial-bounds-leak.rs:34:10
+   |
+LL |     3i32.test(); //~ ERROR
+   |          ^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `test`, perhaps you need to implement it:
+           candidate #1: `Foo`
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/trivial-bounds-leak.rs:35:5
+   |
+LL |     Foo::test(&4i32); //~ ERROR
+   |     ^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+note: required by `Foo::test`
+  --> $DIR/trivial-bounds-leak.rs:15:5
+   |
+LL |     fn test(&self);
+   |     ^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/trivial-bounds-leak.rs:36:5
+   |
+LL |     generic_function(5i32); //~ ERROR
+   |     ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+   |
+note: required by `generic_function`
+  --> $DIR/trivial-bounds-leak.rs:39:1
+   |
+LL | fn generic_function<T: Foo>(t: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors occurred: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/trivial-bounds-lint.rs b/src/test/ui/trivial-bounds-lint.rs
new file mode 100644 (file)
index 0000000..e6988cb
--- /dev/null
@@ -0,0 +1,50 @@
+// 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(trivial_bounds)]
+#![allow(unused)]
+#![deny(trivial_bounds)]
+
+struct A where i32: Copy; //~ ERROR
+
+trait X<T: Copy> {}
+
+trait Y<T>: Copy {}
+
+trait Z {
+    type S: Copy;
+}
+
+// Check only the bound the user writes trigger the lint
+fn trivial_elaboration<T>() where T: X<i32> + Z<S = i32>, i32: Y<T> {} // OK
+
+fn global_param() where i32: X<()> {} //~ ERROR
+
+// Should only error on the trait bound, not the implicit
+// projection bound <i32 as Z>::S == i32.
+fn global_projection() where i32: Z<S = i32> {} //~ ERROR
+
+impl A {
+    fn new() -> A { A }
+}
+
+// Lifetime bounds should be linted as well
+fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+//~^ ERROR
+//~| ERROR
+
+fn local_lifetimes<'a>() where i32: 'a, &'a str: 'a {} // OK
+
+fn global_outlives() where 'static: 'static {} //~ ERROR
+
+// Check that each bound is checked individually
+fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
+
+fn main() {}
diff --git a/src/test/ui/trivial-bounds-lint.stderr b/src/test/ui/trivial-bounds-lint.stderr
new file mode 100644 (file)
index 0000000..6a3e198
--- /dev/null
@@ -0,0 +1,50 @@
+error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:15:1
+   |
+LL | struct A where i32: Copy; //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/trivial-bounds-lint.rs:13:9
+   |
+LL | #![deny(trivial_bounds)]
+   |         ^^^^^^^^^^^^^^
+
+error: Trait bound i32: X<()> does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:28:1
+   |
+LL | fn global_param() where i32: X<()> {} //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Trait bound i32: Z does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:32:1
+   |
+LL | fn global_projection() where i32: Z<S = i32> {} //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:39:1
+   |
+LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound &'static str : 'static does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:39:1
+   |
+LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:45:1
+   |
+LL | fn global_outlives() where 'static: 'static {} //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
+  --> $DIR/trivial-bounds-lint.rs:48:1
+   |
+LL | fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
index adf6b85b6429c57e02a8cdef8d49ef7ac03e9231..b3e79ce2447fb564838d82ea413716b8c7ec8e03 100644 (file)
@@ -14,3 +14,7 @@ fn main() {
 fn foo<T>(x: T, y: T) {
     let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T`
 }
+
+fn bar<T>(x: T) {
+    x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+}
index 777f16b12ce683a4466b607fb344a3035453ec7d..4b01a626814e555a5427e4a316b65d970ef12c8a 100644 (file)
@@ -6,6 +6,17 @@ LL |     let z = x + y; //~ ERROR binary operation `+` cannot be applied to type
    |
    = note: `T` might need a bound for `std::ops::Add`
 
-error: aborting due to previous error
+error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
+  --> $DIR/missing_trait_impl.rs:19:5
+   |
+LL |     x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `T`
+   |
+   = note: `T` might need a bound for `std::ops::AddAssign`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0369`.
+Some errors occurred: E0368, E0369.
+For more information about an error, try `rustc --explain E0368`.
index fb81a7b695d4ef54bec9fb3b863da98aa3ba0e7f..ba80af6c7e037b7739310d06d14d04b020092b8d 100644 (file)
@@ -22,7 +22,7 @@ error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied
   --> $DIR/union-sized-field.rs:23:11
    |
 LL |     Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied
-   |           ^^ `T` does not have a constant size known at compile-time
+   |           ^ `T` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = help: consider adding a `where T: std::marker::Sized` bound
index c05c1cfe4129691bf6d5fd9a8ff6bd0ade15f132..0e18efbf9da3eda5b87c4e8d72e1e123bca283e8 100644 (file)
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `W: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:33:8
    |
 LL |     VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied
-   |        ^^ `W` does not have a constant size known at compile-time
+   |        ^ `W` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `W`
    = help: consider adding a `where W: std::marker::Sized` bound
@@ -22,7 +22,7 @@ error[E0277]: the trait bound `Y: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:35:15
    |
 LL |     VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied
-   |               ^^ `Y` does not have a constant size known at compile-time
+   |               ^ `Y` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = help: consider adding a `where Y: std::marker::Sized` bound
@@ -42,7 +42,7 @@ error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:39:8
    |
 LL |     VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied
-   |        ^^^^^ `[u8]` does not have a constant size known at compile-time
+   |        ^^^^ `[u8]` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: no field of an enum variant may have a dynamically sized type
@@ -60,7 +60,7 @@ error[E0277]: the trait bound `[f32]: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:41:15
    |
 LL |     VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied
-   |               ^^^^^^ `[f32]` does not have a constant size known at compile-time
+   |               ^^^^^ `[f32]` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f32]`
    = note: no field of an enum variant may have a dynamically sized type
@@ -78,7 +78,7 @@ error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfi
   --> $DIR/unsized-enum2.rs:51:8
    |
 LL |     VM(Foo),  //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied
-   |        ^^^^ `Foo + 'static` does not have a constant size known at compile-time
+   |        ^^^ `Foo + 'static` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static`
    = note: no field of an enum variant may have a dynamically sized type
@@ -96,7 +96,7 @@ error[E0277]: the trait bound `FooBar + 'static: std::marker::Sized` is not sati
   --> $DIR/unsized-enum2.rs:53:15
    |
 LL |     VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied
-   |               ^^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
+   |               ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static`
    = note: no field of an enum variant may have a dynamically sized type
@@ -114,7 +114,7 @@ error[E0277]: the trait bound `[i8]: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:57:8
    |
 LL |     VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
    = note: no field of an enum variant may have a dynamically sized type
@@ -132,7 +132,7 @@ error[E0277]: the trait bound `[f64]: std::marker::Sized` is not satisfied
   --> $DIR/unsized-enum2.rs:60:15
    |
 LL |     VS(isize, <&'static [f64] as Deref>::Target),
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f64]`
    = note: no field of an enum variant may have a dynamically sized type
@@ -150,7 +150,7 @@ error[E0277]: the trait bound `PathHelper1 + 'static: std::marker::Sized` is not
   --> $DIR/unsized-enum2.rs:45:8
    |
 LL |     VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied
-   |        ^^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
+   |        ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
    |
    = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static`
    = note: required because it appears within the type `Path1`
@@ -170,7 +170,7 @@ error[E0277]: the trait bound `PathHelper3 + 'static: std::marker::Sized` is not
   --> $DIR/unsized-enum2.rs:47:15
    |
 LL |     VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied
-   |               ^^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
+   |               ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
    |
    = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static`
    = note: required because it appears within the type `Path3`
index 47a85352b0044c0d39c78dd9c0bb35f6c95f2e65..00b4b5c5caa7836de4089968b816401b6f9583ca 100755 (executable)
@@ -26,6 +26,7 @@ if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
     echo "   $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
 fi
 
+MYDIR=$(dirname $0)
 
 BUILD_DIR="$1"
 shift
@@ -33,13 +34,13 @@ shift
 shopt -s nullglob
 
 while [[ "$1" != "" ]]; do
-    MYDIR=$(dirname $1)
     for EXT in "stderr" "stdout" "fixed"; do
         for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do
+            OUT_DIR=`dirname "$1"`
             OUT_BASE=`basename "$OUT_NAME"`
-            if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then
-                echo updating $MYDIR/$OUT_BASE
-                cp $OUT_NAME $MYDIR
+            if ! (diff $OUT_NAME $MYDIR/$OUT_DIR/$OUT_BASE >& /dev/null); then
+                echo updating $MYDIR/$OUT_DIR/$OUT_BASE
+                cp $OUT_NAME $MYDIR/$OUT_DIR
             fi
         done
     done
index e456241f18227c7eb8d78a45daa66c756a9b65e7..c658fc8cbcd1f199edd445a49cb43139ebdc5f02 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7
+Subproject commit c658fc8cbcd1f199edd445a49cb43139ebdc5f02
index 1bac9ef66bb81354e9b25f6e66ae05d916877ad1..4f18f238cab903af72e49191325c5c28ba385e1c 100644 (file)
@@ -2524,7 +2524,7 @@ fn run_rmake_test(&self) {
                 .env("IS_WINDOWS", "1")
                 .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
                 .env("CC", format!("'{}' {}", self.config.cc, cflags))
-                .env("CXX", &self.config.cxx);
+                .env("CXX", format!("'{}'", &self.config.cxx));
         } else {
             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
                 .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
index e0e1bd7ff778e5913b566c9e03224faecc0eb486..6a4c62c1673c3dabcc9a0c99018bd08fec46fda7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486
+Subproject commit 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7
index d2ade31a52a417257742de72c5936a8a342a34b5..3e3df0485004bc1343bc8200b68c67ac7c479b28 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d2ade31a52a417257742de72c5936a8a342a34b5
+Subproject commit 3e3df0485004bc1343bc8200b68c67ac7c479b28
index 25f7a2d1294c5bcec54b06c422ff8f4aa1c4cba3..bc4503903d665589ab3bf1c0beb887bf8eb795ed 100644 (file)
@@ -12,73 +12,148 @@ const fs = require('fs');
 
 const TEST_FOLDER = 'src/test/rustdoc-js/';
 
+function getNextStep(content, pos, stop) {
+    while (pos < content.length && content[pos] !== stop &&
+           (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
+        pos += 1;
+    }
+    if (pos >= content.length) {
+        return null;
+    }
+    if (content[pos] !== stop) {
+        return pos * -1;
+    }
+    return pos;
+}
+
 // Stupid function extractor based on indent.
 function extractFunction(content, functionName) {
-    var x = content.split('\n');
-    var in_func = false;
     var indent = 0;
-    var lines = [];
-
-    for (var i = 0; i < x.length; ++i) {
-        if (in_func === false) {
-            var splitter = "function " + functionName + "(";
-            if (x[i].trim().startsWith(splitter)) {
-                in_func = true;
-                indent = x[i].split(splitter)[0].length;
-                lines.push(x[i]);
-            }
-        } else {
-            lines.push(x[i]);
-            if (x[i].trim() === "}" && x[i].split("}")[0].length === indent) {
-                return lines.join("\n");
+    var splitter = "function " + functionName + "(";
+
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = start;
+        while (pos < content.length && content[pos] !== ')') {
+            pos += 1;
+        }
+        if (pos >= content.length) {
+            break;
+        }
+        pos = getNextStep(content, pos + 1, '{');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            if (content[pos] === '"' || content[pos] === "'") {
+                var stop = content[pos];
+                var is_escaped = false;
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+            } else if (content[pos] === '{') {
+                indent += 1;
+            } else if (content[pos] === '}') {
+                indent -= 1;
+                if (indent === 0) {
+                    return content.slice(start, pos + 1);
+                }
             }
+            pos += 1;
         }
+        content = content.slice(start + 1);
     }
     return null;
 }
 
 // Stupid function extractor for array.
 function extractArrayVariable(content, arrayName) {
-    var x = content.split('\n');
-    var found_var = false;
-    var lines = [];
-
-    for (var i = 0; i < x.length; ++i) {
-        if (found_var === false) {
-            var splitter = "var " + arrayName + " = [";
-            if (x[i].trim().startsWith(splitter)) {
-                found_var = true;
-                i -= 1;
-            }
-        } else {
-            lines.push(x[i]);
-            if (x[i].endsWith('];')) {
-                return lines.join("\n");
+    var splitter = "var " + arrayName;
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = getNextStep(content, start, '=');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        pos = getNextStep(content, pos, '[');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            if (content[pos] === '"' || content[pos] === "'") {
+                var stop = content[pos];
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+            } else if (content[pos] === ']' &&
+                       pos + 1 < content.length &&
+                       content[pos + 1] === ';') {
+                return content.slice(start, pos + 2);
             }
+            pos += 1;
         }
+        content = content.slice(start + 1);
     }
     return null;
 }
 
 // Stupid function extractor for variable.
 function extractVariable(content, varName) {
-    var x = content.split('\n');
-    var found_var = false;
-    var lines = [];
-
-    for (var i = 0; i < x.length; ++i) {
-        if (found_var === false) {
-            var splitter = "var " + varName + " = ";
-            if (x[i].trim().startsWith(splitter)) {
-                found_var = true;
-                i -= 1;
-            }
-        } else {
-            lines.push(x[i]);
-            if (x[i].endsWith(';')) {
-                return lines.join("\n");
+    var splitter = "var " + varName;
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = getNextStep(content, start, '=');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            if (content[pos] === '"' || content[pos] === "'") {
+                var stop = content[pos];
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+            } else if (content[pos] === ';') {
+                return content.slice(start, pos + 1);
             }
+            pos += 1;
         }
+        content = content.slice(start + 1);
     }
     return null;
 }
@@ -101,7 +176,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
     for (var i = 0; i < thingsToLoad.length; ++i) {
         var tmp = funcToCall(fileContent, thingsToLoad[i]);
         if (tmp === null) {
-            console.error('enable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
+            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
             process.exit(1);
         }
         content += tmp;
@@ -160,10 +235,11 @@ function main(argv) {
     // execQuery first parameter is built in getQuery (which takes in the search input).
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
-    var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery",
-                           "execSearch"];
+    var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
+                           "getQuery", "buildIndex", "execQuery", "execSearch"];
 
     finalJS += 'window = { "currentCrate": "std" };\n';
+    finalJS += 'var rootPath = "../";\n';
     finalJS += ALIASES;
     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
     finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
index 0f8029f251b569a010cb5cfc5a8bff8bf3c949ac..db8cb0b8d6942d42a322b1d36b2504977404f362 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0f8029f251b569a010cb5cfc5a8bff8bf3c949ac
+Subproject commit db8cb0b8d6942d42a322b1d36b2504977404f362
index 9a87fcb00d526f4cc683cfbbf98b2bbc9446d0b7..c34cf1bd5ec09691c5993f0ae2facee2205c2eb0 100644 (file)
@@ -59,6 +59,7 @@
 static WHITELIST: &'static [Crate] = &[
     Crate("aho-corasick"),
     Crate("ar"),
+    Crate("arrayvec"),
     Crate("atty"),
     Crate("backtrace"),
     Crate("backtrace-sys"),
     Crate("cc"),
     Crate("cfg-if"),
     Crate("cmake"),
+    Crate("crossbeam-deque"),
+    Crate("crossbeam-epoch"),
+    Crate("crossbeam-utils"),
+    Crate("either"),
     Crate("ena"),
     Crate("env_logger"),
     Crate("filetime"),
@@ -82,7 +87,9 @@
     Crate("log"),
     Crate("log_settings"),
     Crate("memchr"),
+    Crate("memoffset"),
     Crate("miniz-sys"),
+    Crate("nodrop"),
     Crate("num_cpus"),
     Crate("owning_ref"),
     Crate("parking_lot"),
     Crate("regex-syntax"),
     Crate("remove_dir_all"),
     Crate("rustc-demangle"),
+    Crate("rustc-rayon"),
+    Crate("rustc-rayon-core"),
     Crate("scoped-tls"),
+    Crate("scopeguard"),
     Crate("smallvec"),
     Crate("stable_deref_trait"),
     Crate("tempdir"),
index ef8b55186b104e8c0ad67012bbc2cad53d455e91..363d01d964eb5da89624680234f263d03cfddf43 100644 (file)
@@ -22,12 +22,22 @@ pub fn check(path: &Path, bad: &mut bool) {
         &libcore_path,
         &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
         &mut |subpath| {
-            if t!(read_to_string(subpath)).contains("#[test]") {
-                tidy_error!(
-                    bad,
-                    "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`",
-                    subpath.display()
-                );
+            if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
+                match read_to_string(subpath) {
+                    Ok(contents) => {
+                        if contents.contains("#[test]") {
+                            tidy_error!(
+                                bad,
+                                "{} contains #[test]; libcore tests must be placed inside \
+                                `src/libcore/tests/`",
+                                subpath.display()
+                            );
+                        }
+                    }
+                    Err(err) => {
+                        panic!("failed to read file {:?}: {}", subpath, err);
+                    }
+                }
             }
         },
     );